In processes of fabricating microelectronic devices, multiple layers of conducting, semiconducting, and dielectric materials are deposited onto a surface of a substrate in a stepwise fashion. Portions of the layers may be removed, followed by further processing by selectively adding and removing materials, all with great precision. As layers are deposited onto and then removed from the substrate, the uppermost surface of the substrate may become non-planar. Before adding more material, the non-planar surface is sometimes processed by “planarization” to produce a smooth surface for a subsequent layer and processing.
Planarizing or polishing a non-planar surface is a process where material of a non-planar surface is removed to leave a highly planar surface. Planarization is useful to remove undesired surface topography such as a rough (un-even) surface, or defects such as agglomerated materials, crystal lattice damage, scratches, or contaminated layers or materials. In one particular use, planarization removes excess material that has been deposited over a substrate surface to fill features such as channels or holes of a lower layer or layers or holes, if the deposited layer exhibits an un-even surface.
Chemical-mechanical planarization, or chemical-mechanical polishing (CMP), is an established commercial technique for planarize substrates in microdevice fabrication. CMP uses a liquid chemical composition known as a CMP composition, alternately a polishing composition, a polishing slurry, or just slurry, in combination with a CMP pad, to mechanically and chemically remove material from a non-planar substrate surface. A slurry can be typically applied to a substrate by contacting the surface of the substrate with a CMP polishing pad to which the slurry has been applied. Material is typically removed from the substrate surface by a combination of mechanical activity of abrasive material contained in the slurry, and chemical activity of chemical materials of the slurry.
To advance the eternal objective of reducing sizes of microelectronic devices, components that make up the devices must be smaller and must be positioned ever more closely together. Electrical isolation between circuits is important for ensuring optimum semiconductor performance, but becomes increasingly difficult with smaller devices. To that end, various fabrication methods involve etching shallow trenches into a semiconductor substrate and then filling the trenches with insulating material, thereby isolating nearby active regions of an integrated circuit. One example of such a process is referred to as shallow trench isolation (STI). This is a process in which a semiconductor layer is formed on a substrate, shallow trenches are formed in the semiconductor layer via etching or photolithography, and dielectric material is deposited over the etched surface to fill the trenches.
To ensure complete filling of trenches, an excess amount of the dielectric material is deposited over the etched surface. The deposited dielectric material (e.g., a silicon oxide) conforms to the topography of the underlying semiconductor substrate, including at the trenches. Thus, after the dielectric material has been placed, the surface of the deposited dielectric material is characterized by an uneven combination of raised areas of the dielectric material separated by trenches in the dielectric material, the raised areas and trenches of the dielectric material aligning with corresponding raised areas and trenches of the underlying surface. The region of the substrate surface that includes the raised dielectric material and trenches is referred to as a pattern field of the substrate, e.g., as “pattern material,” “pattern oxide,” “pattern dielectric,” etc. This region is characterized by a “step height,” which is the difference in height of the raised areas of the dielectric material relative to the trench height.
Excess dielectric material that makes up the raised areas is removed by a CMP process to produce a planar surface. During removal of the raised area material, an amount of material of the trenches will also be removed. This removal of material from the trenches is referred to as “trench loss.” In a useful process the rate of removal of material from trenches is well below the rate of removal from raised areas. Thus, as material of the raised areas is removed (at a faster rate compared to material being removed from the trenches) the pattern dielectric becomes a highly planarized surface that may be referred to as a “blanket” region of the processed substrate surface, e.g., “blanket dielectric” or “blanket oxide.”
Chemical Mechanical polishing processes for removing pattern dielectric materials can be characterized by performance parameters that include: various polishing rates (i.e., removal rate), trench loss, planarization efficiency, and a highly desired property of “self-stopping” behavior.
Trench loss is the amount (thickness, e.g., in Angstroms (Å)) of material removed from trenches in achieving planarization of pattern material by eliminating an initial step height. Trench loss is calculated as the initial trench thickness minus a final trench thickness.
Removal rate refers to a rate of removal of material from a surface of a substrate and is usually expressed in terms of units of length (thickness) per unit of time (e.g., Angstroms (A) per minute). Different removal rates relating to different regions of a substrate, or to different stages of a polishing step, can be important in assessing process performance. A “pattern removal rate” is the rate of removal of dielectric material from raised areas of pattern dielectric at a stage of a process during which a substrate exhibits a substantial step height. “Blanket removal rate” refers to a rate of removal of dielectric material from a planarized (i.e., “blanket”) dielectric material at an end of a polishing step, when step height has been significantly (e.g., essentially entirely) reduced.
Planarization efficiency relates to trench loss that occurs, per step height reduction, in achieving a planar surface, i.e., step height reduction divided by trench loss.
In various dielectric polishing steps (e.g., of an STI process) the rate of removal of pattern dielectric is typically a rate-limiting factor of the overall process. Therefore, high removal rates of pattern dielectric (the “pattern removal rate”) are desired to increase throughput. Good efficiency in the form of relatively low trench loss is also very important. Further, if the removal rate of dielectric remains high after achieving planarization (i.e., the “blanket removal rate”), overpolishing occurs, resulting in added trench loss.
In certain particularly unique and advantageous processes, overpolishing and associated trench loss can be avoided if a blanket removal rate is especially low. A related and highly desirable performance property is referred to as “self-stopping” behavior. Self-stopping behavior is a highly uncommon process feature, especially in processes that also include high pattern removal rate. In a self-stopping process, when a large percentage of topography thickness (e.g., raised portions) has been removed, the removal rate decreases dramatically. With self-stopping behavior the removal rate is effectively high while a significant step height is present at the substrate surface, but will then become extremely low when the surface becomes effectively planar.
Advantages of self-stopping slurries result from the reduced blanket removal rate, which produces a wide endpoint window. As one practical effect, self-stopping behavior can allow for processing of substrates having reduced dielectric film thickness, allowing for a reduced amount of material to be deposited over a structured lower layer. Also, the need for endpoint detection can be eliminated and planarization can be more efficient. Substrates can be polished with lower trench loss by avoiding overpolishing or unnecessary removal of dielectric after planarization.
Need exists for ongoing improvement in CMP compositions and processes of chemical-mechanical planarization and polishing, including for processing substrates that contain pattern dielectric materials (e.g., silicon oxide). Desired compositions and methods should perform at useful or advantageously high pattern removal rates, while also providing improved planarization efficiency by way of reduced or low levels of trench loss. In highly preferred embodiments, a slurry and process can exhibit self-stopping behavior.


Q:

Loading different Libraries with same Functions dynamically

I have a program which has a reference to an external DLL:
magic.externalFunctions.sql.dll

depending on the target system I might need the following instead:
magic.externalFunctions.nosql.dll

These DLLs are external libraries who offer the same functionality. Even the public methods and properties are the same. But they do not have a combined Interface or base class.
Now I need to chose between these two libraries depending on the target system. If they would have an Interface in common I would do something like:
public class DoDatabaseStuff() {
    private IMagic _magic
    public DoDatabaseStuff(bool useNoSql) {
       if (useNoSql) {
         _magic=new SqlMagic();
       } else {
         _magic=new NoSqlMagic();
       }
       myTable=_magic.Table.Create("CustomerTable");
       myTable.Columns.Add(typeof(int),"ID");
       myTable.Columns.Add(typeof(string),"Name");
   }
}

Is there any way to solve this without using an excessive amount of reflection? I still want to use something like myTable.Columns.Add() instead of tableType.GetMethod("Add").Invoke()...
I also do not want to use conditions in the csproj using different build configurations. While this does work in theory, it gets distroyed every time the csproj changes automatically(e.g. a nuget-package updates)

A:

When you are confronted with bad design that you can not change, a good way to go is to keep that design out of your code. In this case that means that you should create the common interface that your external assemblies are lacking.
You can use adapters to provide a unified interface to keep the initial design flaw out of the core of your code.
You start with creating abstractions for the original classes you want to access:
public interface IMagic {
    ITable CreateTable(string name);
}

public interface ITable {
    void AddColumn(Type type, string name);
}

Then you provide adapters:
class SqlMagicAdapter : IMagic {
    SqlMagic m_innerMagic = new SqlMagic();

    ITable CreateTable(string name) {
        return new SqlTableAdapter(m_innerMagic.Table.Create(name));
    }
}

class SqlTableAdapter : ITable {
    SqlTable m_innerTable;
    public SqlTableAdapter(SqlTable innerTable) {
        m_innerTable = innerTable;
    }
    void AddColumn(Type type, string name) {
        m_innerTable.Columns.Add(type, name);
    }
}

class NoSqlMagicAdapter : IMagic {
    NoSqlMagic m_innerMagic = new NoSqlMagic();

    ITable CreateTable(string name) {
        return new NoSqlTableAdapter(m_innerMagic.Table.Create(name));
    }
}

class NoSqlTableAdapter : ITable {
    NoSqlTable m_innerTable;
    public NoSqlTableAdapter(NoSqlTable innerTable) {
        m_innerTable = innerTable;
    }
    void AddColumn(Type type, string name) {
        m_innerTable.Columns.Add(type, name);
    }

With a factory method you can return the respective adapter:
public static class MagicFactory {
    public static IMagic GetMagic(bool useNoSql) {
        if (useNoSql) {
            return new NoSqlMagic();
        }
        else {
            return new SqlMagic();
        }
    }
}

Your core code can be kept clean by only using the abstractions returned by the factory:
public class DoDatabaseStuff() {
    private IMagic _magic
    public DoDatabaseStuff(bool useNoSql) {
       _magic = MagicFactory.GetMagic(useNoSql);
       ITable myTable = _magic.CreateTable("CustomerTable");
       myTable.AddColumn(typeof(int), "ID");
       myTable.AddColumn(typeof(string), "Name");
   }
}

An added advantage is that you are also ready for any future changes, for example yet another updated external library that is not compatible to the previous ones. You can easily support these new functionalities without changing your core code.


include ../../../components/labels
+label-primary(text)


<?php

// +----------------------------------------------------------------------
// | WeChatDeveloper
// +----------------------------------------------------------------------
// | 版权所有 2014~2020 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://think.ctolog.com
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | github开源项目：https://github.com/zoujingli/WeChatDeveloper
// +----------------------------------------------------------------------

use WeChat\Contracts\BasicWeWork;

include '../include.php';

$config = include 'work-config.php';

try {
    $url = 'https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token=ACCESS_TOKEN';
    $result = BasicWeWork::instance($config)->callGetApi($url);
    echo '<pre>';
    print_r(BasicWeWork::instance($config)->config->get());
    print_r($result);
    echo '</pre>';
} catch (Exception $exception) {
    echo $exception->getMessage() . PHP_EOL;
}


Franken campaign officials said Saturday that Coleman officials are trying to "deprive Minnesota voters of their civil rights."

Andy Barr, Franken's communications director, said in a statement: "Ever since the routine process of canvassing to ensure that every vote is counted began, the Coleman campaign has been attempting to obstruct it. And, in typical fashion, they have now gone to court to shut down the count. This stealth attack on an early Saturday morning is a disgusting attempt to disenfranchise voters who did nothing wrong, and we will fight hard on behalf of Minnesotans who deserve to have their voices heard."

So far it isn't working but Coleman has made it perfectly clear that he doesn't agree with Al Franken that every single legally cast vote must be counted. He's demanded that the state stop counting the ballots sent in by our brave soldiers, sailors, airmen and Marines stationed overseas. These Republicans should all be horsewhipped! Why is he so hysterical? Easy: his tiny 700 vote lead has now shrunk to a 221 advantage and it keeps getting tinier and tinier as counties recheck their numbers and scrutinize each ballot.If Coleman is prevented from his anti-democratic tactics of getting votes thrown out and disenfranchising more people-- a GOP specialty-- he looks like he's headed to certain-- and well-deserved-- defeat. A huge number of undervotes-- votes registered for the presidential race but not for the Senate race-- occurred in three counties, which are all Democratic Party strongholds: Hennepin, Ramsey and St. Louis counties.Coleman will sue over every vote and hope he winds up with a partisan right wing judge to rule in his favor. His goal, of course, is to get the case into the most ideologically extremist court in the country, the horrid Eighth Circuit U.S. Court of Appeals, which has jurisdiction over Minnesota. It's a classic case of a repulsive stacked court. Bush appointed 7 of its 11 members-- all far right loons-- and 2 of the other 4 are also GOP-appointed extremists. There's no chance Minnesota voters would get a fair shake in this Torquemada-like excuse for a court. Expect him to eventually claim that Minnesota's Secretary of State, Mark Ritchie, stole the election for Franken. Anyone who knows Norm Coleman knows one thing for sure: the man has no honor, no dignity and is the Senate's biggest cheat. Franken may not be a real progressive like Jeff Merkley but he will be a reasonable moderate with an open mind a far cry from the knee-jerk conservative Coleman has proven himself to be. And with Jon Kyl already vowing to use the filibuster to block Obama's program, it is more crucial than every to make sure that if Coleman goes back to Washington, it's as a K Street lobbyist and not as a senator.

Labels: Al Franken, Minnesota, Norm Coleman, voter fraud


Q:

How get links from href property using regex

I have a regex expression that returns me all the links from a html file, but it has a problem: instead of returning just the link, like http://link.com, it also returns the href=" (href="http://link.com). What can I do to only get the links without having that href=" ?
This is my regex:
/href="(http|https|ftp|ftps)\:\/\/[-a-zA-Z0-9.]+\.[a-zA-Z]{2,3}(?:\/(?:[^"<=]|=)*)?/g

Full code:
  var source = (body || '').toString();
  var urlArray = [];
  var url;
  var matchArray;

  // Regular expression to find FTP, HTTP(S) URLs.
  var regexToken = /href="(http|https|ftp|ftps)\:\/\/[-a-zA-Z0-9.]+\.[a-zA-Z]{2,3}(?:\/(?:[^"<=]|=)*)?/g;

  // Iterate through any URLs in the text.
  while( (matchArray = regexToken.exec( source )) !== null )
  {
    var token = matchArray[0];
    token = JSON.stringify(matchArray[0]);
    token = matchArray[0].toString();
    urlArray.push([ token ]);
  }

A:

RegExp#exec will store all contents captured by the capturing groups that are defined in your pattern. You may access Group 1 with [1] index.
Use
var token = matchArray[1];

Also, I believe you can shorten the regex to just
/\bhref="((?:http|ftp)[^"]+)"/g

if you are sure the values are always inside double quotes. See this demo.


/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImageMarchingCubes.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkImageMarchingCubes.h"

#include "vtkCellArray.h"
#include "vtkCommand.h"
#include "vtkFloatArray.h"
#include "vtkImageData.h"
#include "vtkImageTransform.h"
#include "vtkInformation.h"
#include "vtkInformationExecutivePortKey.h"
#include "vtkInformationVector.h"
#include "vtkMarchingCubesTriangleCases.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include <cmath>

vtkStandardNewMacro(vtkImageMarchingCubes);

//------------------------------------------------------------------------------
// Description:
// Construct object with initial range (0,1) and single contour value
// of 0.0. ComputeNormal is on, ComputeGradients is off and ComputeScalars is on.
vtkImageMarchingCubes::vtkImageMarchingCubes()
{
  this->ContourValues = vtkContourValues::New();
  this->ComputeNormals = 1;
  this->ComputeGradients = 0;
  this->ComputeScalars = 1;

  this->LocatorPointIds = nullptr;
  this->InputMemoryLimit = 10240; // 10 mega Bytes
}

vtkImageMarchingCubes::~vtkImageMarchingCubes()
{
  this->ContourValues->Delete();
}

// Description:
// Overload standard modified time function. If contour values are modified,
// then this object is modified as well.
vtkMTimeType vtkImageMarchingCubes::GetMTime()
{
  vtkMTimeType mTime = this->Superclass::GetMTime();
  vtkMTimeType contourValuesMTime = this->ContourValues->GetMTime();

  mTime = (contourValuesMTime > mTime ? contourValuesMTime : mTime);

  return mTime;
}

//------------------------------------------------------------------------------
template <class T>
int vtkImageMarchingCubesGetTypeSize(T*)
{
  return sizeof(T);
}

//------------------------------------------------------------------------------
int vtkImageMarchingCubes::RequestUpdateExtent(vtkInformation* vtkNotUsed(request),
  vtkInformationVector** inputVector, vtkInformationVector* vtkNotUsed(outputVector))
{
  // start with an empty UPDATE_EXTENT to ensure proper streaming
  // (the UPDATE_EXTENT will be set properly in RequestData()).
  int extent[6] = { 0, -1, 0, -1, 0, -1 };
  vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
  inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), extent, 6);
  return 1;
}

//------------------------------------------------------------------------------
int vtkImageMarchingCubes::RequestData(vtkInformation* vtkNotUsed(request),
  vtkInformationVector** inputVector, vtkInformationVector* outputVector)
{
  // get the info objects
  vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation* outInfo = outputVector->GetInformationObject(0);

  // get the input and output
  vtkImageData* inData = vtkImageData::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkPolyData* output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));

  vtkDemandDrivenPipeline* inputExec =
    vtkDemandDrivenPipeline::SafeDownCast(vtkExecutive::PRODUCER()->GetExecutive(inInfo));

  vtkIdType numContours = this->ContourValues->GetNumberOfContours();
  double* values = this->ContourValues->GetValues();

  vtkDebugMacro("Starting Execute Method");

  // Gradients must be computed (but not saved) if Compute normals is on.
  this->NeedGradients = this->ComputeGradients || this->ComputeNormals;

  // Determine the number of slices per request from input memory limit.
  int minSlicesPerChunk, chunkOverlap;
  if (this->NeedGradients)
  {
    minSlicesPerChunk = 4;
    chunkOverlap = 3;
  }
  else
  {
    minSlicesPerChunk = 2;
    chunkOverlap = 1;
  }
  inputExec->UpdateInformation();
  // Each data type requires a different amount of memory.
  vtkIdType temp;
  switch (inData->GetScalarType())
  {
    vtkTemplateMacro(temp = vtkImageMarchingCubesGetTypeSize(static_cast<VTK_TT*>(nullptr)));
    default:
      vtkErrorMacro(<< "Could not determine input scalar type.");
      return 1;
  }

  // Get the WHOLE_EXTENT and divide it into chunks
  int extent[6];
  inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), extent);
  // multiply by the area of each slice
  temp *= extent[1] - extent[0] + 1;
  temp *= extent[3] - extent[2] + 1;
  // temp holds memory per image. (+1 to avoid dividing by zero)
  this->NumberOfSlicesPerChunk = static_cast<int>(this->InputMemoryLimit * 1024 / (temp + 1));
  if (this->NumberOfSlicesPerChunk < minSlicesPerChunk)
  {
    vtkWarningMacro("Execute: Need " << minSlicesPerChunk * (temp / 1024) << " KB to load "
                                     << minSlicesPerChunk << " slices.\n");
    this->NumberOfSlicesPerChunk = minSlicesPerChunk;
  }
  vtkDebugMacro("Execute: NumberOfSlicesPerChunk = " << this->NumberOfSlicesPerChunk);
  this->NumberOfSlicesPerChunk -= chunkOverlap;

  // Create the points, scalars, normals and Cell arrays for the output.
  // estimate the number of points from the volume dimensions
  vtkIdType estimatedSize = static_cast<vtkIdType>(extent[1] - extent[0] + 1);
  estimatedSize *= static_cast<vtkIdType>(extent[3] - extent[2] + 1);
  estimatedSize *= static_cast<vtkIdType>(extent[5] - extent[4] + 1);
  estimatedSize = static_cast<vtkIdType>(pow(1.0 * estimatedSize, 0.75));
  estimatedSize = (estimatedSize / 1024) * 1024; // multiple of 1024
  if (estimatedSize < 1024)
  {
    estimatedSize = 1024;
  }
  vtkDebugMacro(<< "Estimated number of points/triangles: " << estimatedSize);
  this->Points = vtkPoints::New();
  this->Points->Allocate(estimatedSize, estimatedSize / 2);
  this->Triangles = vtkCellArray::New();
  this->Triangles->AllocateEstimate(estimatedSize, 1);
  if (this->ComputeScalars)
  {
    this->Scalars = vtkFloatArray::New();
    this->Scalars->Allocate(estimatedSize, estimatedSize / 2);
  }
  if (this->ComputeNormals)
  {
    this->Normals = vtkFloatArray::New();
    this->Normals->SetNumberOfComponents(3);
    this->Normals->Allocate(3 * estimatedSize, 3 * estimatedSize / 2);
  }
  if (this->ComputeGradients)
  {
    this->Gradients = vtkFloatArray::New();
    this->Gradients->SetNumberOfComponents(3);
    this->Gradients->Allocate(3 * estimatedSize, 3 * estimatedSize / 2);
  }

  // Initialize the internal point locator (edge table for one image of cubes).
  this->InitializeLocator(extent[0], extent[1], extent[2], extent[3]);

  // Loop through the chunks running marching cubes on each one
  int zMin = extent[4];
  int zMax = extent[5];
  for (int chunkMin = zMin, chunkMax; chunkMin < zMax; chunkMin = chunkMax)
  {
    // Get the chunk from the input
    chunkMax = chunkMin + this->NumberOfSlicesPerChunk;
    if (chunkMax > zMax)
    {
      chunkMax = zMax;
    }
    extent[4] = chunkMin;
    extent[5] = chunkMax;
    // Expand if computing gradients with central differences
    if (this->NeedGradients)
    {
      --extent[4];
      ++extent[5];
    }
    // Don't go over boundary of data.
    if (extent[4] < zMin)
    {
      extent[4] = zMin;
    }
    if (extent[5] > zMax)
    {
      extent[5] = zMax;
    }
    // Get the chunk from the input
    inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), extent, 6);
    inputExec->Update();

    this->March(inData, chunkMin, chunkMax, numContours, values);
    if (!this->AbortExecute)
    {
      this->UpdateProgress(static_cast<double>(chunkMax - zMin) / (zMax - zMin));
    }

    if (vtkDataObject::GetGlobalReleaseDataFlag() ||
      inInfo->Has(vtkStreamingDemandDrivenPipeline::RELEASE_DATA()))
    {
      inData->ReleaseData();
    }
  }

  // Put results in our output
  vtkDebugMacro(<< "Created: " << this->Points->GetNumberOfPoints() << " points, "
                << this->Triangles->GetNumberOfCells() << " triangles");
  output->SetPoints(this->Points);
  this->Points->Delete();
  this->Points = nullptr;
  output->SetPolys(this->Triangles);
  this->Triangles->Delete();
  this->Triangles = nullptr;
  if (this->ComputeScalars)
  {
    int idx = output->GetPointData()->AddArray(this->Scalars);
    output->GetPointData()->SetActiveAttribute(idx, vtkDataSetAttributes::SCALARS);
    this->Scalars->Delete();
    this->Scalars = nullptr;
  }
  if (this->ComputeNormals)
  {
    output->GetPointData()->SetNormals(this->Normals);
    this->Normals->Delete();
    this->Normals = nullptr;
  }

  // Recover extra space.
  output->Squeeze();

  vtkImageTransform::TransformPointSet(inData, output);

  // release the locators memory
  this->DeleteLocator();

  return 1;
}

//------------------------------------------------------------------------------
// This method uses central differences to compute the gradient
// of a point. Note: This method assumes that max > min for all 3 axes!
// It does not consider the dataset spacing.
// b0 (b1, b2) indicates the boundary conditions for the three axes.:
// b0 = -1 => pixel is on x axis minimum of region.
// b0 = 0 => no boundary conditions
// b0 = +1 => pixel is on x axis maximum of region.
template <class T>
void vtkImageMarchingCubesComputePointGradient(
  T* ptr, double* g, int inc0, int inc1, int inc2, short b0, short b1, short b2)
{
  if (b0 < 0)
  {
    g[0] = (double)(ptr[inc0]) - (double)(*ptr);
  }
  else if (b0 > 0)
  {
    g[0] = (double)(*ptr) - (double)(ptr[-inc0]);
  }
  else
  {
    g[0] = (double)(ptr[inc0]) - (double)(ptr[-inc0]);
  }

  if (b1 < 0)
  {
    g[1] = (double)(ptr[inc1]) - (double)(*ptr);
  }
  else if (b1 > 0)
  {
    g[1] = (double)(*ptr) - (double)(ptr[-inc1]);
  }
  else
  {
    g[1] = (double)(ptr[inc1]) - (double)(ptr[-inc1]);
  }

  if (b2 < 0)
  {
    g[2] = (double)(ptr[inc2]) - (double)(*ptr);
  }
  else if (b2 > 0)
  {
    g[2] = (double)(*ptr) - (double)(ptr[-inc2]);
  }
  else
  {
    g[2] = (double)(ptr[inc2]) - (double)(ptr[-inc2]);
  }
}

//------------------------------------------------------------------------------
// This method interpolates vertices to make a new point.
template <class T>
int vtkImageMarchingCubesMakeNewPoint(vtkImageMarchingCubes* self, int idx0, int idx1, int idx2,
  int inc0, int inc1, int inc2, T* ptr, int edge, int* imageExtent, double value)
{
  int edgeAxis = 0;
  T* ptrB = nullptr;
  double temp, pt[3];

  // decode the edge into starting point and axis direction
  switch (edge)
  {
    case 0: // 0,1
      ptrB = ptr + inc0;
      edgeAxis = 0;
      break;
    case 1: // 1,2
      ++idx0;
      ptr += inc0;
      ptrB = ptr + inc1;
      edgeAxis = 1;
      break;
    case 2: // 3,2
      ++idx1;
      ptr += inc1;
      ptrB = ptr + inc0;
      edgeAxis = 0;
      break;
    case 3: // 0,3
      ptrB = ptr + inc1;
      edgeAxis = 1;
      break;
    case 4: // 4,5
      ++idx2;
      ptr += inc2;
      ptrB = ptr + inc0;
      edgeAxis = 0;
      break;
    case 5: // 5,6
      ++idx0;
      ++idx2;
      ptr += inc0 + inc2;
      ptrB = ptr + inc1;
      edgeAxis = 1;
      break;
    case 6: // 7,6
      ++idx1;
      ++idx2;
      ptr += inc1 + inc2;
      ptrB = ptr + inc0;
      edgeAxis = 0;
      break;
    case 7: // 4,7
      ++idx2;
      ptr += inc2;
      ptrB = ptr + inc1;
      edgeAxis = 1;
      break;
    case 8: // 0,4
      ptrB = ptr + inc2;
      edgeAxis = 2;
      break;
    case 9: // 1,5
      ++idx0;
      ptr += inc0;
      ptrB = ptr + inc2;
      edgeAxis = 2;
      break;
    case 10: // 3,7
      ++idx1;
      ptr += inc1;
      ptrB = ptr + inc2;
      edgeAxis = 2;
      break;
    case 11: // 2,6
      ++idx0;
      ++idx1;
      ptr += inc0 + inc1;
      ptrB = ptr + inc2;
      edgeAxis = 2;
      break;
  }

  // interpolation factor
  temp = (value - *ptr) / (*ptrB - *ptr);

  // interpolate the point position
  switch (edgeAxis)
  {
    case 0:
      pt[0] = (double)idx0 + temp;
      pt[1] = (double)idx1;
      pt[2] = (double)idx2;
      break;
    case 1:
      pt[0] = (double)idx0;
      pt[1] = (double)idx1 + temp;
      pt[2] = (double)idx2;
      break;
    case 2:
      pt[0] = (double)idx0;
      pt[1] = (double)idx1;
      pt[2] = (double)idx2 + temp;
      break;
  }

  // Save the scale if we are generating scalars
  if (self->ComputeScalars)
  {
    self->Scalars->InsertNextValue(value);
  }

  // Interpolate to find normal from vectors.
  if (self->NeedGradients)
  {
    short b0, b1, b2;
    double g[3], gB[3];
    // Find boundary conditions and compute gradient (first point)
    b0 = (idx0 == imageExtent[1]);
    if (idx0 == imageExtent[0])
    {
      b0 = -1;
    }
    b1 = (idx1 == imageExtent[3]);
    if (idx1 == imageExtent[2])
    {
      b1 = -1;
    }
    b2 = (idx2 == imageExtent[5]);
    if (idx2 == imageExtent[4])
    {
      b2 = -1;
    }
    vtkImageMarchingCubesComputePointGradient(ptr, g, inc0, inc1, inc2, b0, b1, b2);
    // Find boundary conditions and compute gradient (second point)
    switch (edgeAxis)
    {
      case 0:
        ++idx0;
        b0 = (idx0 == imageExtent[1]);
        break;
      case 1:
        ++idx1;
        b1 = (idx1 == imageExtent[3]);
        break;
      case 2:
        ++idx2;
        b2 = (idx2 == imageExtent[5]);
        break;
    }
    vtkImageMarchingCubesComputePointGradient(ptrB, gB, inc0, inc1, inc2, b0, b1, b2);
    // Interpolate Gradient
    g[0] = g[0] + temp * (gB[0] - g[0]);
    g[1] = g[1] + temp * (gB[1] - g[1]);
    g[2] = g[2] + temp * (gB[2] - g[2]);
    if (self->ComputeGradients)
    {
      self->Gradients->InsertNextTuple(g);
    }
    if (self->ComputeNormals)
    {
      temp = -1.0 / sqrt(g[0] * g[0] + g[1] * g[1] + g[2] * g[2]);
      g[0] *= temp;
      g[1] *= temp;
      g[2] *= temp;
      self->Normals->InsertNextTuple(g);
    }
  }

  return self->Points->InsertNextPoint(pt);
}

//------------------------------------------------------------------------------
// This method runs marching cubes on one cube.
template <class T>
void vtkImageMarchingCubesHandleCube(vtkImageMarchingCubes* self, int cellX, int cellY, int cellZ,
  vtkImageData* inData, T* ptr, int numContours, double* values)
{
  vtkIdType inc0, inc1, inc2;
  int valueIdx;
  double value;
  int cubeIndex, ii;
  vtkIdType pointIds[3];
  vtkMarchingCubesTriangleCases *triCase, *triCases;

  vtkInformation* inInfo = self->GetExecutive()->GetInputInformation(0, 0);

  triCases = vtkMarchingCubesTriangleCases::GetCases();

  inData->GetIncrements(inc0, inc1, inc2);
  for (valueIdx = 0; valueIdx < numContours; ++valueIdx)
  {
    value = values[valueIdx];
    // compute the case index
    cubeIndex = 0;
    if ((double)(ptr[0]) > value)
    {
      cubeIndex += 1;
    }
    if ((double)(ptr[inc0]) > value)
    {
      cubeIndex += 2;
    }
    if ((double)(ptr[inc0 + inc1]) > value)
    {
      cubeIndex += 4;
    }
    if ((double)(ptr[inc1]) > value)
    {
      cubeIndex += 8;
    }
    if ((double)(ptr[inc2]) > value)
    {
      cubeIndex += 16;
    }
    if ((double)(ptr[inc0 + inc2]) > value)
    {
      cubeIndex += 32;
    }
    if ((double)(ptr[inc0 + inc1 + inc2]) > value)
    {
      cubeIndex += 64;
    }
    if ((double)(ptr[inc1 + inc2]) > value)
    {
      cubeIndex += 128;
    }
    // Make sure we have trianlges
    if (cubeIndex != 0 && cubeIndex != 255)
    {
      // Get edges.
      triCase = triCases + cubeIndex;
      EDGE_LIST* edge = triCase->edges;
      // loop over triangles
      while (*edge > -1)
      {
        for (ii = 0; ii < 3; ++ii, ++edge) // insert triangle
        {
          // Get the index of the point
          pointIds[ii] = self->GetLocatorPoint(cellX, cellY, *edge);
          // If the point has not been created yet
          if (pointIds[ii] == -1)
          {
            int* extent = inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT());

            pointIds[ii] = vtkImageMarchingCubesMakeNewPoint(
              self, cellX, cellY, cellZ, inc0, inc1, inc2, ptr, *edge, extent, value);
            self->AddLocatorPoint(cellX, cellY, *edge, pointIds[ii]);
          }
        }
        self->Triangles->InsertNextCell(3, pointIds);
      } // for each triangle
    }
  }
}

//------------------------------------------------------------------------------
template <class T>
void vtkImageMarchingCubesMarch(vtkImageMarchingCubes* self, vtkImageData* inData, T* ptr,
  int chunkMin, int chunkMax, int numContours, double* values)
{
  int idx0, idx1, idx2;
  int min0, max0, min1, max1, min2, max2;
  vtkIdType inc0, inc1, inc2;
  T *ptr0, *ptr1, *ptr2;
  unsigned long target, count;

  // avoid warnings
  (void)ptr;

  // Get information to loop through images.
  inData->GetExtent(min0, max0, min1, max1, min2, max2);
  ptr2 = (T*)(inData->GetScalarPointer(min0, min1, chunkMin));
  inData->GetIncrements(inc0, inc1, inc2);

  // Setup the abort interval
  target = (unsigned long)((max0 - min0 + 1) * (max1 - min1 + 1) / 50.0);
  ++target;
  count = 0;

  // Loop over all the cubes
  for (idx2 = chunkMin; idx2 < chunkMax; ++idx2)
  {
    ptr1 = ptr2;
    for (idx1 = min1; idx1 < max1; ++idx1)
    {
      if (!(count % target))
      {
        if (self->GetAbortExecute())
        {
          return;
        }
      }
      count++;
      // continue with last loop
      ptr0 = ptr1;
      for (idx0 = min0; idx0 < max0; ++idx0)
      {
        // put magnitudes into the cube structure.
        vtkImageMarchingCubesHandleCube(self, idx0, idx1, idx2, inData, ptr0, numContours, values);

        ptr0 += inc0;
      }
      ptr1 += inc1;
    }
    ptr2 += inc2;
    self->IncrementLocatorZ();
  }
}

//------------------------------------------------------------------------------
// This method calls the proper templade function.
void vtkImageMarchingCubes::March(
  vtkImageData* inData, int chunkMin, int chunkMax, int numContours, double* values)
{
  void* ptr = inData->GetScalarPointer();

  switch (inData->GetScalarType())
  {
    vtkTemplateMacro(vtkImageMarchingCubesMarch(
      this, inData, static_cast<VTK_TT*>(ptr), chunkMin, chunkMax, numContours, values));
    default:
      vtkErrorMacro(<< "Unknown output ScalarType");
      return;
  }
}

//============================================================================
// These method act as the point locator so vertices will be shared.
// One 2d array of cubes is stored. (z dimension is ignored).
// Points are indexed by their cube and edge.
// Shared edges are only represented once.  Cubes are responsible for
// edges on their min faces.  Their is an extra row and column of cubes
// to store the max edges of the last row/column of cubes,

//------------------------------------------------------------------------------
// This method allocates and initializes the point array.
// One 2d array of cubes is stored. (z dimension is ignored).
void vtkImageMarchingCubes::InitializeLocator(int min0, int max0, int min1, int max1)
{
  // Free old memory
  delete[] this->LocatorPointIds;

  // Extra row and column
  this->LocatorDimX = (max0 - min0 + 2);
  this->LocatorDimY = (max1 - min1 + 2);
  this->LocatorMinX = min0;
  this->LocatorMinY = min1;
  // 5 non shared edges.
  vtkIdType size = 5;
  size *= static_cast<vtkIdType>(this->LocatorDimX);
  size *= static_cast<vtkIdType>(this->LocatorDimY);
  this->LocatorPointIds = new vtkIdType[size];
  // Initialize the array
  for (vtkIdType idx = 0; idx < size; ++idx)
  {
    this->LocatorPointIds[idx] = -1;
  }
}

//------------------------------------------------------------------------------
// This method frees the locators memory.
void vtkImageMarchingCubes::DeleteLocator()
{
  // Free old memory
  delete[] this->LocatorPointIds;
  this->LocatorPointIds = nullptr;
}

//------------------------------------------------------------------------------
// This method moves the Z index of the locator up one slice.
void vtkImageMarchingCubes::IncrementLocatorZ()
{
  vtkIdType* ptr = this->LocatorPointIds;
  for (int y = 0; y < this->LocatorDimY; ++y)
  {
    for (int x = 0; x < this->LocatorDimX; ++x)
    {
      ptr[0] = ptr[4];
      ptr[3] = ptr[1];
      ptr[1] = ptr[2] = ptr[4] = -1;
      ptr += 5;
    }
  }
}

//------------------------------------------------------------------------------
// This method adds a point to the array.  Cube is the X/Y cube,
// segment is the index of the segment (same as marching cubes).(XYZ)
// (0,0,0)->(1,0,0): 0,  (1,0,0)->(1,1,0): 1,
// (1,1,0)->(0,1,0): 2,  (0,1,0)->(0,0,0): 3,
// (0,0,1)->(1,0,1): 4,  (1,0,1)->(1,1,1): 5,
// (1,1,1)->(0,1,1): 6,  (0,1,1)->(0,0,1): 7,
// (0,0,0)->(0,0,1): 8,  (1,0,0)->(1,0,1): 9,
// (0,1,0)->(0,1,1): 10, (1,1,0)->(1,1,1): 11.
// Shared edges are computed internally. (no error checking)
void vtkImageMarchingCubes::AddLocatorPoint(int cellX, int cellY, int edge, vtkIdType ptId)
{
  // Get the correct position in the array.
  vtkIdType* ptr = this->GetLocatorPointer(cellX, cellY, edge);
  *ptr = ptId;
}

//------------------------------------------------------------------------------
// This method gets a point from the locator.
vtkIdType vtkImageMarchingCubes::GetLocatorPoint(int cellX, int cellY, int edge)
{
  // Get the correct position in the array.
  vtkIdType* ptr = this->GetLocatorPointer(cellX, cellY, edge);
  return *ptr;
}

//------------------------------------------------------------------------------
// This method returns a pointer to an ID from a cube and an edge.
vtkIdType* vtkImageMarchingCubes::GetLocatorPointer(int cellX, int cellY, int edge)
{
  // Remove redundant edges (shared by more than one cube).
  // Take care of shared edges
  switch (edge)
  {
    case 9:
      ++cellX;
      edge = 8;
      break;
    case 10:
      ++cellY;
      edge = 8;
      break;
    case 11:
      ++cellX;
      ++cellY;
      edge = 8;
      break;
    case 5:
      ++cellX;
      edge = 7;
      break;
    case 6:
      ++cellY;
      edge = 4;
      break;
    case 1:
      ++cellX;
      edge = 3;
      break;
    case 2:
      ++cellY;
      edge = 0;
      break;
  }

  // relative to min and max.
  cellX -= this->LocatorMinX;
  cellY -= this->LocatorMinY;

  // compute new indexes for edges (0 to 4)
  // must be compatible with LocatorIncrementZ.
  if (edge == 7)
  {
    edge = 1;
  }
  if (edge == 8)
  {
    edge = 2;
  }

  // return correct pointer
  return this->LocatorPointIds + edge +
    (cellX + cellY * static_cast<vtkIdType>(this->LocatorDimX)) * 5;
}

//------------------------------------------------------------------------------
int vtkImageMarchingCubes::FillInputPortInformation(int, vtkInformation* info)
{
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkImageData");
  return 1;
}

//------------------------------------------------------------------------------
void vtkImageMarchingCubes::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);

  this->ContourValues->PrintSelf(os, indent.GetNextIndent());

  os << indent << "ComputeScalars: " << this->ComputeScalars << "\n";
  os << indent << "ComputeNormals: " << this->ComputeNormals << "\n";
  os << indent << "ComputeGradients: " << this->ComputeGradients << "\n";

  os << indent << "InputMemoryLimit: " << this->InputMemoryLimit << "K bytes\n";
}


Q:

Same tube for 23mm and 28mm tires?

I like to change my tires with the Continental 4000S II 28mm width tires.
Do I need new tubes for the wider tires or can I use my old ones from my 23mm tires?

A:

A tube will have a range.  Most likely the original range of that tube did not include 28.  Small tubes are usually sold as 19-23.  Yes the rubber would probably stretch to 28 without bursting but it would definitely be weak.  If you are going to spend money on new tires then spend money on new tubes.  Even same size I put new tubes in new tires.  Save the old for emergency.  Better yet save the old tires with tubes for emergency unless the tires are just plain shot.


Read More

Speaking about the incident and on receiving the commendation, Mr Phara said: “Initially I thought it was a terrorist attack, I heard screaming and a taxi driver had ran in telling me that a man had been stabbed. I ran out to see what was happening.

John Phare

“I could see that the man was being stabbed, I just didn’t think, and I rugby tackled Skinner to the ground.

Read More

Mr Phare, who has worked with GWR for the past seven years, said: “You never expect to be faced with something like this and I never intervened to be acknowledged or recognised. I just wish I could have done more.”


I have three obsessions: Recording gear, DIY CNC and woodwork. There are never enough hours in the day. I designed this machine 2 years ago and started to collect offcuts of the extrusion and other bits and pieces together, and then for a while, not much really happened.

Until this year. Six months ago I thought “this is getting ridiculous – I am getting nothing done”. So I took a more proactive approach to my hobbies. I started to frantically buy all the bits and pieces for the audio gear that this place has inspired me to build. And I decided that I had to finish my latest CNC so I can machine all of my panels (and eventually mic bodies).

Then a few months back I learned that my wife and daughter would be doing a little traveling, and I would have 10 whole days where I could do what I want. I decided that this was the deadline to have my machine finished. So until now, and to the slight detriment to marital harmony and other things I should really be doing, I have been spending any spare moment building and getting ready for what I have called my “CNC Extravaganza”.

The CNC Extravaganza has just started, and I think it is time to start sharing it with you guys.

By the end of next weekend I am hoping to have machined my first G9 panels, and with a bit of luck panels for some 9k, API and one bottle pres. And why not some 1176’s and LA2A’s as well. The boards are etched and the parts are waiting.

This is the CAD design as of two years ago. A lot of it is “tab and slot” laser cut steel construction. The gantry is fixed, which makes the thing a lot more rigid, which is important for machining metals. Many of the parts were salvaged from going in the bin (offcuts, the electrical cabinet, etc) and many were purchased from our favourite online auction house. If I use “cheap” as a description, it came from ebay.

I fully assembled all of the mechanical parts to check that everything works, and then pulled it apart for painting. I then made a pretty dodgy stand to hold the electrical cabinet and keep the thing mobile. Here it is after being painted. The X axis is assembled and all the rest is laid out (on my first woodworking CNC) waiting for the final assembly:

Here are some of the steel parts, most of which is for the carriage and Z axis:

Gantry Added along with the Y axis carriage:

Next was to assemble the Z axis, with energy chain and spindle. On the kind advice from Pete from grand master audio I decided to splash out on a mist coolant system. He also advised me on some tooling, of which I now have plenty ready to go. The spindle is a cheap 1.5KW, but I think I got lucky – it seems to spin nice and smoothly.

Close-up of the Z axis:

More wiring and fitting of servos, but still some tidying up to do:

X axis drive and limit switch:

Y axis drive:

And this brings me to now. The extravaganza has begun. What is left to do is wire up the electrical cabinet, do a little more tidying up of the wiring, and then it will be time to fire it up!

The next job to tackle:

And the back view as of this morning.

More photos and eventually some video's to come.

Cheers, and let’s get some more of you guys into CNC – it is almost as addictive as building audio gear!

I see another cnc router in one of those pics! Fun stuff. Who did your steel work? Its great.. I spent a good 2 years on my machine as well. It has evolved over time and wasnt thought out as yours! Cant wait to see it cut. What are you expecting to get in terms of rapids?

I did not achieve as much today as I had hoped because of the lathe I picked up (see another post. it was HEAVY!)

But I got most of the control cabinet done.....

This pic is before going into the cabinet. Yep, still some tidying up to do, and that dodgy cabletied PSU on the left is temporary.

And into the cabinet, with the switches and indicators wired up.......

It is amazing how quickly a cabinet fills up. I thought there would be plenty of room. My control system friends would probably cringe.

Some of the switches and lights are unused for now - there are not enough lines in the parallel port, so eventually I will have to put another parallel port card in the PC. I bought one already, but it is so dodgy and I do not see it working (capacitors snapped off the board). Get what you pay for I guess.

It is alive!..........

Well sort of.

It is midnight. when I powered it up it tripped the RCD. Lucky I Found a matchbox to illuminate the way out of my workshop.

And then I remembered having a problem with a VSD tripping a RCD at work a couple of years ago (and I think it was the same brand), so I hope that I can sort that out. I have another VSD on my dust collector for my woodworking machines (it is a WEG), and that one does not trip the RCD, so worst case I swap them over and throw out the nice shiny new delta.

So the above pic is with the VSD breaker switched off.

Now I just need to sort out the VSD issue, finish drilling the gland plate, and then wire in the looms.

Eric, I do the steel work my self. I can not weld, but the tab and slot construction makes sure that everything goes together OK. And once I grind all the evidence away, i get away with it.

Joshco..... I have the air cooled one.

SO today's update.... Not as much done as I had planned. The machine is finished and everything is operational. The VSD problem is sorted, and everything is working correctly. I am jogging around nicely. The next step is to tweak all of the settings (ill know the final rapid speed then), and then make some G code for it. I am sure that will take longer than I expect. But I am still optimistic for a G9 by the end of the week.

Those stepper/servo controllers are pretty cool, a bit spendy but compared to ac servos not bad. From what I can tell the actual controller for the stepper is in the same place as the sensor? Also are you using Mach3 or LinuxCNC??(EMC) Very nice engraving, I would love to see it mill some aluminum. I think we have a new source for front panels!!

Eric, They are indeed cool motors. Everything is built in, the encoder and all of the electronics. I just give them 48v and the step and direction signals. I found out about them through my day job and have used them for doing scale models or prototypes of systems or mechanism that I am working out how to control. While they are stepper motors, they have encoders and have some kind of clever control inbuilt that makes them perform like servos. In my day job they are great because I can give them a velocity or torque set point in much the same way that you control large VSD's. At work, I am currently using them in a small model of something I am trying to work out how to control, and on the real thing the drives are 275kW.

So anyway, the guy that makes them is pretty friendly and good with support, so when I found out that he had incorporated step and direction control, I decided they were perfect for my machine. Yep they cost more than the ebay steppers and drives, but these ones are closed loop so I do not expect to suffer from missed steps like i did on the old machine.

Ptownkid, The coolant device is a "koolmist" which I bought from the US. It is a bit tricky to adjust, but I think it will get better when I put a check valve on it so the coolant does not flow back to the bottle. It was a bit of an impulse buy, and after I had bought it,I discovered a couple of others on the market, but I'm sure it will work out. Koolmist sell their own lube, but because of shipping costs, I found some locally in OZ.

Anyway, moving towards something audio........!

Last night I tried engraving a couple of things, but the tool paths were not ideal (lesson learned - join all of the little vectors!).

Here is a closeup of a non audio related thing I'm trying to engrave (part of a wedding gift for my brother in law)......

And I just did up a first audio panel......Not perfect. it only took half an hour. I now have a sample of anodized ali so Ill be engraving and cutting it tomorrow. It will be intersting to see how it turns out compared to the soft (welding grade?) aluminium offcuts that I have used to now (the above pictures just looks like brass because of the lighting).

If all goes well, I am going to try and profile the outside edges (cleanup) and put on a bevel around the outside as well.

Videos will come eventually, but I just need to find the best way and the time to get them uploaded somewhere.

Well today is the last day of my CNC extravaganza. I will soon be reunited with my family.

Yesterday was good....

It will never end up being used. The font was not ideal for engraving. I think it will take a while to come up with a short list of the best (but not boring) fonts for engraving. What you can not see in this pic is that I profiled around the outside and the cut is nice and smooth (much nicer than the guillotine finish).

And I will come clean. I snapped a bit - see the divot under the infinity sign. I paused the machine to change the tool length slightly (the holes were not going all the way through) and then mach3 went a bit crazy when I tried to restart. But even after a restart and a new tool, it was bang on. Gotta love good homing switches.

Fantastic.... wish my first attempts had been that successful.... wasted lots of metal and broke lots of bits when I first started.

Methylated spirit is an excellent lubricant for engraving aluminium... also, search the net for "single line engraving fonts".... they engrave much quicker and often look better (and you can make them smaller).... you should be able to get some free to download ones.

I was just finishing up a long reply, with breakdown of costs etc etc.... and then my browser disappeared. aaaarrrrggghhh!

So this one will not be as long.

On the issue of cost, I estimate that to build a machine like mine, and if you had to buy everything (but got hold of some bargains) it would cost around 5k. For me though I was able to get the aluminum extrusion as free offcuts, and lots of electrical gear salvaged from the trash where I used to work, so it did not cost anywhere near that much.

If you are interested, I will do a breakdown of costs when I am not so angry at this laptop.

There are places where you can save money, places where it is not worth trying to save money, and places where you just need to get lucky. For example, cheap ballscrews and linear bearings can be found, but you need to be a bit lucky with quality. I have found a good Chinese supplier that seems to be OK. In contrast, I bought some spare 16LU bearings from an Australian supplier and they are unusable. Also, I would never go back to open loop steppers again, so there is somewhere where I would not try to save.

But I will say this. The hobby of CNC could easily take up as much time and money as DIY audio so if you are just looking for quick cheap panels, forget it! If you are looking for the chemical free high that I experienced when my machine did not miss a beat for 1 hour and my G9 panel appear before my eyes, jump in!

I designed mine to do 19" panels, up to 8U high (not sure why) but if you only want to do 51x size stuff there are OK looking machines on ebay that can be had for around a grand, but then I would spend a bit upgrading the drives, possibly the spindle and home switches. but that will certainly start to add up. And do not forget to put $400 aside for some tooling and material to get started with.

Colin, yep I hear you on the single line fonts. I spent a while looking into those years ago with the woodworking machine, and particularly with the small stuff It will be the go. Back then the single line fonts were essential because I could not expect the machine to run for an hour without missing steps. It would come back to do the first letter in the sentence and it would be out of line. The EVO drives don't miss steps, so for my initial trials it was nice to be able to choose any type of font (like for my "G9 dirty" emblem.

And I will also be experimenting with Meths as a lube. The jury is out on whether the misting system was all that nessesary. I need to put some solenoid valves close to the actual unit so the fluid does not siphon back down to the bottle (need this for CNC use)


Abatements

Abatements are available to new and expanding industries in DeKalb County. These abatements are for non-educational property taxes and are granted by city or county authorities. In order to receive an abatement, the business must follow certain procedures and have a qualifying project.

To qualify, the business must be one of the following industry classification codes:

A trade or business described in 1987 Standard Industrial Classification Industry Group Number 0724, Major Groups 20 to 39, inclusive, 50 and 51, Industrial Group Number 737, and Industry Numbers 4613, 8731, 8733, and 8734.

A trade or business described in the 1997 North American Industry Classification System within Subsector 493 (Warehousing and Storage), Industry Number 488310 (Port and Harbor Operations), or Industry Number 488320 (Marine Cargo Handling).

How to File for an Abatement

Abatements are granted through the city or county governing bodies. The Alabama Department of Revenue’s Abatement Booklet contains procedures, forms, and instructions for applying for an abatement.

Once an abatement has been granted, the owner or private user of an industrial property must file with the County Revenue Commissioner’s Office a copy of the resolution from the city or county governing body.


Ischemic versus pharmacologic hepatic preconditioning.
Hepatic ischemia-reperfusion injury has a significant impact on liver resection and transplantation. Many strategies have been developed to reduce the effects of ischemia-reperfusion injury, including pharmacologic and ischemic preconditioning; however, studies comparing these two methods are lacking. An experimental study was performed in a swine model. Eighteen swine were randomly assigned to three different groups: an ischemic preconditioning (IschPC) group, a pharmacologic preconditioning (PharmPC) group, and a control group. All animals underwent a 40-min liver ischemia, followed by 40 min of reperfusion. The IschPC group received a short period of ischemia (10 min) and a short period of reperfusion (15 min) before prolonged ischemia. The PharmPC group received inhaled sevoflurane for 30 min before prolonged ischemia. The control group did not receive any intervention before prolonged ischemia. Blood samples and liver tissue were obtained after ischemic and reperfusion periods. Injury was evaluated by measure of DNA damage (using COMET assay) and serum biochemical markers (transaminases, alkaline phosphatase, amylase, bilirubin, and C-reactive protein [CRP]). No significant difference was found in serum biochemical markers, except for the C-reactive protein level that was lower in the PharmPC group than in the control group soon after hepatic ischemia. Soon after prolonged ischemia, DNA damage index, both in blood samples and in liver tissue samples, was similar among the groups. However, an increase in DNA damage after reperfusion was higher in the control group than in the PharmPC group (P < 0.05). The increase in DNA damage in the IschPC group was half of that observed in the control, but this difference was not statistically significant. Our results suggest an early protective effect of PharmPC (lower levels of C-reactive protein soon after ischemia). The protective effect observed after reperfusion was higher with PharmPC than with ischemic preconditioning. The simultaneous use of both methods could potentiate protection for ischemia-reperfusion.


[Spontaneous cutaneous cysto-hepato-bronchial fistula caused by a hydatid cyst. Apropos of a case].
We report a case liver hydatid cyst which fistulized simultaneously and spontaneously to the skin and in the bronchia observed in a 70-years-old woman. Outcome was favorable after surgical intervention. It is an extremely rare and original case.


PhoenixRC

from Runtime Games Ltd

What is PhoenixRC? (from Runtime Games Ltd)

Phoenix RC Flight Simulators are realistic flight sims that will teach you how to fly an RC airplane, without the expense of crashing the real thing while you learn. Phoenix is available in a version with a real RC transmitter, or in a version where you use your own transmitter. Phoenix has over 100 beautifully modeled... Read more

Overview

PhoenixRC is a program developed by Runtime Games Ltd. The most used version is 4.0.10, with over 98% of all installations currently using this version. A scheduled task is added to Windows Task Scheduler in order to launch the program at various scheduled times (the schedule varies depending on the version). The main program executable is phoenixRC.exe. The software installer includes 28 files and is usually about 2.26 MB (2,364,688 bytes). In comparison to the total number of users, most PCs are running the OS Windows 7 (SP1) as well as Windows 8. While about 53% of users of PhoenixRC come from the United States, it is also popular in United Kingdom and Canada.

Program details

URL: www.phoenix-sim.com

Help link: www.phoenix-sim.com

Installation folder: C:\Program Files\PhoenixRC\

Uninstaller: MsiExec.exe /X{7A03BEDC-6390-440E-8D13-721A22F0BD1F}

(The Windows Installer is used for the installation, maintenance, and removal.)


2*d**2 + 2*d - 2*d - 2 - 13*d**2 to m*d + i + u*d**2 and give u.
-15
Express -5 - 8 - 3*h + 5 in the form d*h + u and give d.
-3
Express (2 - 1 + 2)*(7 + 6*a - 7) as l + w*a and give w.
18
Rearrange -5*p - 2 + 43*p**3 + p**4 + 2 - 46*p**3 - p**2 to the form c*p + t*p**3 + r*p**4 + w*p**2 + g and give c.
-5
Express -z**2 - 2 + 2*z**3 - 4*z + z - 3*z**4 - z**2 + 2*z**4 as o + v*z**4 + a*z**2 + q*z**3 + u*z and give u.
-3
Rearrange -4*t**2 - 4*t + 0*t**3 - t**3 + 0*t**2 + 8*t**2 to x*t**3 + s*t + b + a*t**2 and give s.
-4
Rearrange (-3 + 3 - 5*n)*(-4*n + 2 - 2)*(-n + 3 - 3) to q*n**2 + z*n**3 + u*n + f and give z.
-20
Rearrange 7 + 2 - 9 + 53*i to g + o*i and give o.
53
Rearrange 2*q + 0*q + 6*q to b*q + r and give b.
8
Express -680 + 682 + 2*u**4 + 3*u - u**2 - 5*u in the form o + y*u + n*u**2 + k*u**4 + r*u**3 and give o.
2
Rearrange (40*y**2 - 40*y**2 + 9*y**3)*(0*y + 0*y + 6*y + (-4 + 3 + 0)*(3*y - y + 0*y) - 2*y - 2 + 2) to n*y + z*y**3 + w*y**4 + x + o*y**2 and give w.
18
Rearrange -2*r**2 + 2*r - 7*r - 5*r**3 + 3*r + 0*r**3 to the form w*r**3 + u*r + o + g*r**2 and give g.
-2
Express (-11 - 13 + 8)*(-7*r - 42 + 42)*(3*r**2 + r**2 - 2*r**2) in the form u + m*r**2 + x*r**3 + c*r and give x.
224
Express -2*r**4 - 3*r - 13 - 9*r + 10*r as l*r**2 + m*r**3 + q*r + h*r**4 + y and give y.
-13
Rearrange 19 + 24 - 2*a**3 - 46 to l*a + h*a**3 + t + y*a**2 and give h.
-2
Rearrange (0*j + j + 4*j)*(3*j**2 - 5*j**3 + 16*j**3 - 8*j**3) to l*j**4 + y*j + u*j**3 + w*j**2 + q and give l.
15
Express -4*q - 14 + q + 12 as m*q + k and give k.
-2
Rearrange -2*k + k**2 + 0 - k - 2 + 5*k**2 - 3*k**2 - 3*k**2 + (k - 3*k - 2*k)*(-3*k + k + 3*k) to l*k + o*k**2 + i and give i.
-2
Rearrange -m**2 + 2*m + 4*m**3 + m**2 + 3*m**2 to a*m**3 + n*m**2 + d*m + b and give n.
3
Express 4*w - w**2 - 3 + 4*w - 6*w as p + m*w + l*w**2 and give l.
-1
Express -2*a**2 - 2*a**2 + 3*a**2 + (3 + 2 - 6)*(-3*a**2 + 0*a**2 + a**2) - 13*a**2 - 19*a**2 + 7*a**2 in the form n + m*a**2 + z*a and give m.
-24
Rearrange 24 - 13 - 13 + 3*p**2 to the form g*p + j*p**2 + k and give j.
3
Express (2*i - 4*i - 4*i)*(-3 + i + 3) + 2 + i**2 - 2 + (1 + 1 - 3)*(i**2 - i**2 - 2*i**2) as y*i + u + w*i**2 and give w.
-3
Express -126 - 26*a + 126 - 69*a in the form o*a + w and give o.
-95
Express -8 - 5 + 5*k**2 + 12 + (-3 + k + 3)*(0*k + k + 0*k) + 2*k**2 - 1 + 1 as s + d*k**2 + p*k and give s.
-1
Express q - 4*q - 23*q**2 + 3*q in the form v*q + d + y*q**2 and give y.
-23
Rearrange 6*f**2 + 0*f + 0*f + (0 + 1 + 0)*(0*f**2 - f**2 - 2*f**2) to the form y*f**2 + l*f + q and give y.
3
Rearrange -4*z**4 + z + 3*z**4 - 16*z**3 + z**2 + 18*z**3 - 2*z to the form k + b*z**2 + d*z**3 + l*z + g*z**4 and give b.
1
Rearrange 7*k**3 - 9 + 9 - k**3 + 1 - 1 + (2*k**2 + 2*k**2 - 5*k**2)*(-3 + 3 + 2*k) + 0*k**2 - k**3 + 0*k**2 to the form t*k**3 + i*k**2 + a*k + v and give t.
3
Express (-46 + 46 + 5*f)*(-4 + 4 + 2 - 2*f) as t*f + z*f**2 + u and give t.
10
Rearrange (10*c - 2*c + 35*c)*(-4*c**2 + 3*c - 3*c) - 2*c**3 + 4*c**3 - c**3 to z*c**2 + x + n*c + j*c**3 and give j.
-171
Rearrange 15 + a**2 - 16 - 5*a**2 - a**2 to z + w*a**2 + c*a and give w.
-5
Rearrange (26*c**2 - 6*c**2 + 11*c**2)*((1 + 0 - 3)*(1 - 1 + 2) + (0 + 2 - 3)*(2 - 3 + 0)) to s*c**2 + r + v*c and give s.
-93
Express p**2 - p - p**3 + 113*p**4 - 2*p**2 + 111*p**4 - 231*p**4 - 2 as u*p**2 + h*p**3 + z*p + c*p**4 + l and give u.
-1
Express (19 - 4 + 6)*((2*o - o + 0*o)*(5 + 0 - 4) + 0*o + 2*o - o) in the form a + z*o and give z.
42
Rearrange -2*j - 8 - 16*j**3 - 7 + 12 to the form t*j + u*j**2 + q + n*j**3 and give n.
-16
Rearrange (2 + y + 2*y - 4*y)*(-5 + y + 5 + 1) to z*y**2 + w*y + q and give q.
2
Rearrange 2 - p**2 - 181*p + 3*p**2 + 195*p to the form q*p + n + j*p**2 and give n.
2
Rearrange (-5 + 3 + 4)*(-1 - 2*n + 0*n + 2) to the form y + m*n and give m.
-4
Express (5*r + 7*r + 10*r)*(-1 + 3 - 3)*(-r**2 + 0*r**2 - r**2) + 4*r**3 - 3*r**3 + 6*r**3 in the form f + u*r**2 + q*r + z*r**3 and give z.
51
Express -1 + 4*c - 3 + 8*c - c as z + x*c and give x.
11
Rearrange (2*l - 5*l + 2*l)*(-2 + 0 - 3)*(8*l + l + 0*l)*(-3 + 4 - 3) to the form w*l**2 + h + q*l and give w.
-90
Rearrange 46*w + 305 - 305 to p*w + j and give p.
46
Rearrange 218*h**2 - 227*h**2 + h - 2 - h to q + t*h + m*h**2 and give q.
-2
Rearrange 2*r**3 - 1 - r**3 + 5*r**2 + 2*r**3 to p + t*r**2 + k*r + o*r**3 and give p.
-1
Rearrange 55*q**2 - 255 + 255 to the form j + p*q**2 + i*q and give p.
55
Express (6*z - 4*z + 0*z)*(3*z - 3*z + 4*z**2)*(1 + 0 - 4) in the form d*z**3 + h + v*z + c*z**2 and give d.
-24
Express -309*k + 309*k - 11*k**2 in the form b*k + z*k**2 + x and give b.
0
Express (-18 + 11*a + 18)*(2*a**2 + 1 - 1 + (6*a**2 - a**2 - 3*a**2)*(1 + 0 + 0) - 3*a**2 + 3*a**2 - 2*a**2) as p*a**3 + h*a**2 + u*a + d and give p.
22
Express 3*l + 0*l - l + (-2*l + 6*l - 3*l)*(-3 + 5 - 1) + 1 - 1 - l + 4*l - 3*l - 3*l + (-1 + 4 - 5)*(0*l - 2*l + 3*l) as q + n*l and give n.
-2
Express 8*u**2 + 3*u**2 + 11*u**2 + 7*u**2 in the form q*u**2 + g*u + a and give g.
0
Express 2*h + 3*h**3 - 3*h**3 + 3*h**3 - 6*h**3 - h**2 as r + m*h + j*h**3 + b*h**2 and give m.
2
Express 10*w - 5*w**2 - 10*w + (0 + 1 + 1)*(-3*w + 3*w + w**2) - w**2 - 2*w**2 + 8*w**2 in the form g*w + y + q*w**2 and give q.
2
Express (11*n - n - n)*(-n**3 - 5*n + 5*n) as d*n**3 + m*n**2 + l + t*n**4 + a*n and give t.
-9
Express (4*d + 0*d - d)*(0 + 3 + 2) - 6*d + 0*d + 4*d in the form i + k*d and give k.
13
Express (2*m**2 - 2*m**2 - m**2)*(-m + 5*m - 3*m)*(-4 - 1 + 6) - 3 + 2 - m**3 + 3 as k*m + j + t*m**2 + g*m**3 and give j.
2
Rearrange -r**2 - 2*r**3 + 0*r + r**4 + 7*r**4 - 6*r**4 - r to the form m + d*r**4 + l*r + a*r**2 + y*r**3 and give d.
2
Express -26*o + 33*o - 24*o in the form x*o + t and give x.
-17
Express -3*i + 5*i**3 - 1 - 1 + 2*i + 0 as p*i**2 + t + n*i + j*i**3 and give j.
5
Rearrange (4 - 2*b - 4 + (3 - 2 + 0)*(4*b - 2*b - 5*b))*(-2*b + 2*b + 3*b**2) to w*b**2 + a + m*b**3 + x*b and give a.
0
Rearrange s**3 - 6*s + 2*s**3 + 6*s - 4 to the form k*s**3 + a + m*s + o*s**2 and give a.
-4
Rearrange (l + 3 - 3)*(541*l - 541*l + 21*l**3) to the form y + x*l**3 + h*l + o*l**2 + p*l**4 and give p.
21
Rearrange -2*y - 1 - 48*y**2 + 95*y**2 - 49*y**2 to the form g*y**2 + s*y + l and give g.
-2
Rearrange (2*z + 0 + 0)*(2*z + z - z) - 104*z + 104*z - 15*z**2 to the form w + p*z + d*z**2 and give d.
-11
Rearrange 5*w - 2*w - w to the form o + m*w and give m.
2
Express -51 - i + 23 + 26 in the form f*i + a and give a.
-2
Rearrange -22*d**2 + 6*d**2 + 109 - 109 to v*d + a*d**2 + l and give a.
-16
Rearrange -3*m - 3*m - 33 + 7*m + 0*m to the form k + c*m and give k.
-33
Rearrange -32 + 6*p - 16 - 2*p - 3*p to the form q + o*p and give o.
1
Rearrange (w - 5*w + w)*(4 - 2 + 3 + (3 + 1 - 3)*(1 + 0 + 0) + 2 + 1 - 4 + 1 - 2 + 2 + 1 - 1 + 1) to i + h*w and give h.
-21
Rearrange (5 - 5 + 4)*(h - 3*h + 3*h) + 2*h - 4*h + h to g + v*h and give g.
0
Express (0*c + 4*c**2 - 2*c**2 + 2*c)*(6*c + 4*c + 2*c)*(0 + 0 - c) as t + g*c**4 + a*c**3 + y*c**2 + m*c and give a.
-24
Express (4*c - 7*c + 4*c)*(83 - 3*c - 66 + 6*c) - 6*c**2 + 4*c**2 + 4*c**2 in the form i*c + x + j*c**2 and give i.
17
Express (m**2 + 0*m**2 - 2*m**2)*(-2 + 2 - 4*m) - 3*m**3 + 4*m**3 - 2*m**3 as r + o*m + g*m**3 + z*m**2 and give g.
3
Rearrange 1 - 1 + v + (v - v + 2*v)*(-93 + 73 + 51) to the form q*v + k and give q.
63
Rearrange 4*v + 2*v**4 - 2*v**2 - 3*v + 0*v**4 - 6*v to w*v + b*v**4 + u + n*v**3 + m*v**2 and give b.
2
Express (4 - 2 + 0)*(0*k**2 - 2*k**2 - k**2)*(1 + 4*k + 2*k - 4*k) in the form x*k**2 + f + z*k + w*k**3 and give x.
-6
Express (0*p - 3*p + p)*(-2 + 3 - 2*p**2 - 3) as i*p**2 + z*p + j + b*p**3 and give z.
4
Rearrange 103*h**2 + 95*h**2 - 3*h + h + h**4 - 183*h**2 + 2*h**3 to the form i + j*h**2 + x*h + k*h**3 + z*h**4 and give z.
1
Rearrange 2*t**4 + t**4 - 1 - 4*t**2 - 9*t + 14*t + 2*t**2 to h*t**4 + n*t**3 + b*t**2 + x + v*t and give x.
-1
Rearrange -2*n**2 + n**4 - 3 + 1 + n**3 - 3 + 0*n**4 to the form o*n**3 + k*n + q + w*n**4 + c*n**2 and give o.
1
Rearrange (5*u**3 - u**3 - 3*u**3)*((5 - 4 + 2)*(-3 + 4 - 3) - 1 - 3 + 0) to c*u + d + f*u**3 + y*u**2 and give y.
0
Rearrange 4 + 3*w**4 + 0 - 2*w**3 - 5*w + 4*w**3 - 6 to the form u + y*w**4 + j*w**2


Links

Images

Classifications

H03K5/00—Manipulating pulses not covered by one of the other main groups in this subclass

H03K5/125—Discriminating pulses

H03K5/1252—Suppression or limitation of noise or interference

Abstract

A digital system for providing a series of pulses that are related to the angular position of an engine crankshaft. A square wave signal is developed which is applied to the input of a synchronous digital filter. The digital filter provides a noise-immune output signal. The digital filter has two counters or timers which are used to determine whether or not the high and low times of the input signal that is applied to the filter exceed predetermined time periods. Based on this determination the filter ignores or passes pulses of the square wave to the output of the filter.

Description

This invention relates to a digital system for providing digital pulses at certain positions of an engine crankshaft and more particularly to a digital system that has a synchronous digital filter to provide noise immunity.

When a magnetic pickup is used to detect crankshaft or camshaft position of an internal combustion engine the pickup coil may be subjected to magnetic fields that cause noise voltages to be developed. Thus, an unwanted voltage may be induced in the pickup coil which if processed will cause an error voltage to be developed. Where the voltage induced in the pickup coil controls the timing of an ignition system and where the ignition coil of the ignition system is located near the pickup coil the magnetic field developed by the coil may induce spurious signals. Further, the magnetic field developed by the ignition coil may cause noise problems in the digital electronics that responds to the voltage induced in the pickup coil and noise voltages can be developed in the digital electronics by various other noise sources.

An asynchronous digital filter for providing noise immunity for a type of system that has been described is disclosed in U.S. patent application Ser. No. 65,956, filed on June 24, 1987, now U.S. Pat. No. 4,843,580 granted on June 27, 1989. In that patent application a digital pulse developing system is disclosed that develops pulses at certain crankshaft positions which has a digital filter that is capable of ignoring voltage pulses that are caused by noise while passing valid pulses that are not caused by noise. The system monitors or measures time periods that correspond to the times that a digital signal is at a one or high level or at a zero or low level. The system determines whether valid one or valid zero levels have occurred by determining whether or not the time periods that the signal is high or low is longer than a predetermined time period. If the signal remains at a one level for longer than a predetermined period of time a valid one level is recognized or achieved. Likewise, if the signal remains at a low or zero level for longer than a predetermined period of time a valid zero level is recognized or achieved. When the digital signal has been at a valid one level and then goes low the system will process this falling edge immediately. The now existing zero level must then be held for the predetermined length of time before any subsequent logical one states are recognized.

The digital filter of the above-referenced patent application is capable of filtering out noise induced positive glitches, that is noise induced voltage pulses that begin with a zero to one level transition. Thus, a one level occurring after a valid zero state has been recognized must remain at a one level for the predetermined length of time before it is considered a valid one state, otherwise it is completely ignored.

The present invention is concerned with providing a digital filter of the type disclosed in the above-referenced patent application wherein the filter is implemented as a synchronous digital filter instead of an asynchronous digital filter of the type disclosed in the above-referenced patent application. By using synchronous circuitry for the digital filter the testing of the filter and in particular fault testing becomes much simpler as compared with asynchronous circuitry. In order to easily test a circuit, one must be able to control the timing events of the circuit. Since in a synchronous system the timing can be controlled by a system clock, the testing is much easier. Further, since timing can be controlled by a clock the logic circuitry of a synchronous system can be frozen in any desired logic state. Another advantage of synchronous circuitry, as opposed to asynchronous circuitry, is that synchronous circuitry can be more reliable and predictable since process variations in manufacturing the integrated semiconductor circuit, that make up the filter, do not effect the timing of the circuit. Thus, synchronous circuitry uses only a system clock to generate timing events whereas asynchronous circuitry use delay paths to generate timing events. These delay paths are provided by one-shot multivibrators which have RC circuits and the response of these RC circuits can vary with process variations.

It accordingly is an object of this invention to provide a digital filter that performs the functions described above that is implemented by synchronous circuitry.

Another object of this invention is to provide a digital filter that is capable of performing the functions described above wherein the filter has two digital timers or ripple counters that are utilized to determine whether or not an input signal to the digital filter has been respectively at valid high and low levels for predetermined periods of time.

IN THE DRAWINGS

FIG. 1 illustrates an ignition system for an internal combustion engine that has a digital pulse developing system made in accordance with this invention;

FIG. 2 is a schematic circuit diagram of a digital filter which is shown as a block in FIG. 1; and

FIG. 3 illustrates waveforms that are useful in understanding this invention.

Referring now to the drawings and more particularly to FIG. 1, an ignition system for an internal combustion engine is illustrated which utilizes the synchronous digital filter of this invention. In FIG. 1, the reference numeral 10 designates a spark-ignited internal combustion engine that has a crankshaft. The crankshaft drives a disk or wheel 12 which has six slots that are spaced by 60 degrees. The disk 12 forms part of a magnetic or variable reluctance pickup that has a pickup coil 14. When a slot passes the pickup coil 14 an alternating voltage designated as 16 is induced in coil 14. These alternating voltages occur at every 60 degrees of rotation of the crankshaft of the engine.

The alternating voltage 16 is applied to a squaring circuit 18 which has a zero crossing detector. The circuit 18 develops a square-wave voltage 20 that is applied to line 22. This square-wave voltage has one level to zero level transitions 20A (falling edges) that are spaced by 60 degrees. The line 22 is connected to a digital filter 24 which is illustrated as a block in FIG. 1. A detailed schematic of digital filter 24 is illustrated in FIG. 2. The output of digital filter 24 is applied to a line 26. As will be more fully described, the digital filter 24 operates to filter out noise induced voltage pulses that begin with a positive transition (zero level to one level). The filter also operates in such a manner that when the digital signal has been at a valid one level and then goes low the filter will process this falling edge immediately. When no noise induced transitions occur the falling edges or negative transitions of the square wave voltage on line 26 follows and is in phase with the falling edges of the input voltage on line 22.

The line 26 is connected to an ignition control circuit 28 which develops and controls the application of spark firing voltages to the spark plugs 30 of engine 10. The ignition control controls an inductive ignition system that has a plurality of ignition coils (not illustrated) that are connected to the spark plugs. The system is a known distributorless system wherein a secondary winding of an ignition coil is connected to two spark plugs which are fired in series. The falling edges or negative transitions of the square-wave voltage on line 26 are used to identify the correct ignition coil to be energized in order to correctly fire a given pair of spark plugs in synchronism with crankshaft position. Ignition control 28 is energized by a direct voltage source 32 of a motor vehicle which is illustrated as a battery. The battery is charged by a direct voltage charging system in a known manner. Direct voltage source 32 supplies the other electronic components of the system by connections which are not illustrated.

The square-wave output voltage on line 26 is applied to a Tach-Counter 40 by line 34. The Tach-Counter 40 receives clock pulses from a constant frequency clock pulse source 41 via line 36 which may have a frequency of 31.25 KHz. The Tach-Counter 40 counts clock pulses for 60 degree intervals to provide a count that represents engine rpm or speed. The counter 40, together with suitable logic circuitry (not illustrated) provides output signals on lines 42 and 43 that are a function of engine speed. The lines 42 and 43 are connected to the digital filter 24 and the logic state of lines 42 and 43, which is a function of engine speed, determines the magnitude of time periods that are used by the digital filter 24 in a manner that will be described. The clock pulse source 41 is connected to digital filter 24 by a line 37.

FIG. 2 illustrates the digital filter 24, shown as a block in FIG. 1, and it will now be described. In FIG. 2, the same reference numerals have been used as were used in FIG. 1 to identify corresponding lines or conductors. In FIG. 2 the input line 22, which has the square-wave voltage 20 applied thereto, is connected to NAND gate 44 and to a NOR gate 45.

The line 37, which is connected to clock 41, is connected to an input of NOR gate 46. The output of NOR gate 46 is connected to the CB input of a flip-flop 48. The Q terminal of flip-flop 48 is connected to the CB terminal of a flip-flop 50 and the Q terminal of flip-flop 50 is connected to the CB terminal of a flip-flop 52. The reset terminal R of flip-flops 48-52 are connected to a line 54 that is connected to the output of NAND gate 44. One of the inputs to gate 44 is connected to a power on reset line 56 via line 58. Flip-flops 48, 50 and 52 are all D-type flip-flops and flip-flops 48 and 50 have their D input tied to its QB output. Flip-flop 52 has its D input tied to the VDD supply (not illustrated).

The synchronous digital filter has logic control or decode lines 60 and 62. These lines are connected to inputs of a NOR gate 64. The lines 62 and 64 are energized with five volts via field effect transistors 66 and 68. The line 60 is connected to three fild effect transistors 70, 71 and 72. The drain-source circuits of transistors 70-72 are connected respectively between line 60 and ground so that when any of these transistors are biased conductive, line 60 is grounded or is placed at a low or zero logic level.

The line 62 is connected to four field effect transistors 73, 74, 75 and 76 and when any of these transistors are biased conductive, line 62 is grounded or is placed at a low or zero logic level.

The gate of transistor 70 is connected to the QB output of flip-flop 48. The gate of transistor 74 is connected to the Q output of flip-flop 48. The QB and Q outputs of flip-flop 50 are connected respectively to the gates of transistors 75 and 71. The QB and Q outputs of flip-flop 52 are connected respectively to the gates of transistors 72 and 76. The gate of transistor 73 is connected to a line 77 which in turn is connected to line 43.

As will be more fully described hereinafter, the flip-flops 48-52 operate as a three stage ripple counter.

The synchronous filter has another three stage ripple counter comprised of flip-flops 78, 79 and 80 which are connected together as shown in FIG. 2. Flip-flops 78 and 79 are the same as flip-flops 48 and 50 and flip-flop 80 is the same as flip-flop 52. Associated with flip-flops 78-80 are logic control or decode lines 81 and 82. The lines 81 and 82 are energized with five volts via field effect transistors T1 and T2. The line 81 is connected to three field effect transistors 83, 84 and 85. The drain source circuits of transistors 83-85 are connected respectively between line 81 and ground so that when any of these transistors are biased conductive, line 81 is grounded or is placed at a low or zero logic level.

The line 82 is connected to four field effect transistors 86, 87, 88 and 89 and when any of these transistors are biased conductive, line 82 is grounded or is placed at a low or zero logic level.

The Q and QB outputs of flip-flop 78 are connected respectively to the gates of transistors 83 and 87. The Q and QB outputs of flip-flop 79 are connected respectively to the gates of transistors 84 and 88. The Q and QB outputs of flip-flop 80 are connected respectively to the gates of transistors 89 and 85. The gate of transistor 86 is connected to line 77 and hence to line 43.

The reset terminals R of flip-flops 78-80 are connected to line 90. Line 90 is connected to the output of NOR gate 91. One of the inputs to gate 91 is connected to a line 92 via line 93. The other input to gate 91 is connected to the output of gate 45. The CB input of flip-flop 78 is connected to the clock line 37 via inverter 94 and line 95.

The decode lines 81 and 82 are connected to inputs of a NOR gate 96. The other input to gate 96 is connected to line 42 via line 97. Line 97 also connects an input of gate 64 to line 42.

The output of gate 96 is connected to an input of NAND gate 100. The other input of gate 100 is connected to power on reset line 56. The output of gate 100 is connected to the reset terminal R of a flip-flop 102. Flip-flop 102 is the same as flip-flop 52. The QB terminal of flip-flop 102 is connected to an input of gate 45 by line 103 and its CB terminal is connected to output line 26 by line 105. The Q output of flip-flop 102 is connected to one of the inputs of a NOR gate 104 by line 107. The output of gate 64 is connected to another input of gate 104 via line 106. The line 54 is connected to another input of gate 104. The output of gate 64 is connected to an input of NOR gate 108 via line 109. The other input of gate 108 is connected to line 92 and the output of gate 108 is connected to an input of gate 46.

The operation of the synchronous digital filter shown in FIG. 2 will now be described. Before proceeding to a detailed description of the operation of the logic circuitry of FIG. 2, reference will be had to FIG. 3 which illustrates waveforms that are useful in understanding the operation of the circuit shown in FIG. 2. In FIG. 3, the input waveform, which is generally designated as 110, is a hypothetical waveform of a square-wave signal that could occur on input line 22. The output waveform of the digital filter on line 26 is depicted in FIG. 3 and generally designated as 112.

First of all, it can be seen in FIG. 3 that the filter 24 operates such that a positive going input signal, which has less than a predetermined high-time duration, will be ignored and hence will not appear at output line 26. Thus, it can be seen that positive going input pulse 114 has been ignored or in other words, produces no corresponding output transition in the output waveform 112. This is because the duration of time that pulse 114 was at a high level was less than a predetermined time. Pulse 114 represents a positive going noise pulse and it is filtered out as has been described.

The filter 24 operates such that any negative going transition of input waveform 110 will be acted upon with the output going low, provided that the negative going transition has been preceded by a valid high-time. A valid high-time means that the input signal has been at a high level for a predetermined period of time. Further, once a negative transition is acted upon, no further input changes or transitions will be recognized until a valid, predetermined low-time is seen. A valid low-time means that the input signal has been at a low level for a predetermined period of time. With this in mind, it can be seen in FIG. 3 that input waveform 110 has a negative going transition 118 and that the output follows this transition as designated by negative going transition 120. The reason that transition 120 is developed by the filter is that there has been a valid high-time preceding transition 118. A valid high-time means that the input waveform was at a high level for at least a predetermined duration of time preceding the negative transition 118. In this case, the waveform 110 was at a high level for the duration of time between transitions 122 and 118 and this duration of time is long enough to be considered a valid high-time.

Following transition 118, the input waveform makes a positive going transition 124. As mentioned above, when a negative transition occurs no further changes will be recognized until a valid, predetermined low-time is seen. In the case of waveform 110 the low-time is the duration of time between transitions 118 and 124. This low-time is assumed to be greater than a valid predetermined low-time and accordingly there is an output transition in output waveform 112 designated as 125.

When negative input transition 126 occurs, a corresponding negative transition 128 occurs in the output. This is because transition 126 was preceded by a valid high-time. Subsequently occurring input pulses 130 and 132 are both ignored because they were not preceded by a valid low time. The pulse 130 meets the high time requirement but since the low time requirement has not been met, the output stays low. The pulse 132 would not make the output go high even if a previously valid low time were attained since its high time is too short. When negative going transition 134 occurs, a corresponding transition 136 occurs in the output. This is because transition 134 was preceded by a valid high-time corresponding to the time duration between transitions 138 and 134.

The filtering action of the digital filter is dependent upon engine speed. At engine speeds above 4000 rpm there is no filtering action. Thus, at engine speeds above 4000 rpm the Tach-counter 40 causes line 42 to go high which causes the output of gate 64 to be held low and flip-flop 102 is kept reset. As a result of the foregoing, the decode lines are bypassed and the output signal on line 26 follows the input signal on line 22.

At engine speeds below 2000 rpm the output of Tach-counter 40 causes line 42 to go low and line 43 to go high. The high level signal on line 43 and hence on line 77 causes transistors 73 and 86 to be biased conductive thereby respectively connecting lines 62 and 82 to ground. This disables decode lines 62 and 82. Decode lines 60 and 81 are enabled.

At engine speeds between 2000 rpm and 4000 rpm the output of Tach-counter 40 causes both lines 42 and 43 to go low. When line 43 goes low, both transistors 73 and 86 are biased nonconductive so that decode lines 62 and 82 are enabled. Decode lines 60 and 81 are also now enabled.

Assume that engine speed is below 2000 rpm so that decode lines 62 and 82 are disabled and decode lines 60 and 81 are enabled. Assume further that the input signal on line 22 is low. The signal on the R inputs of flip-flops 48-52 will now be high which will keep or maintain the flip-flops in a reset condition. In this reset condition the flip-flops are reset to a zero count and cannot be clocked by the clock pulses on line 37 while in the reset condition. When the input signal subsequently goes high, the reset signal to the flip-flops goes low and the flip-flops will now start counting clock pulses from line 37. Thus, the fact that the R terminals went low allows the flip-flops to be clocked by the clock pulses. Decode line 60 will stay low until transistors 70-72 have all been biased nonconductive. This occurs when the three stage ripple counter comprised of flip-flops 48-52 has counted up to a preset count magnitude of five clock pulses which corresponds to a time period of about 119 to 171 microseconds. This is the valid high-time period. When the preset count magnitude has been counted, a decode has been reached and decode line 60 will then go from a low level to a high level. This forces the output of gate 64 to go from high to low which allows the output of gate 104 to go high. Once a decode is reached, the output of gate 64 feeds back to gate 46 via line 109 and gate 108 to terminate the supply of clock pulses to flip-flop 48 thereby maintaining the outputs of flip-flops 48-52 at the decode count. This allows the output on line 26 to go and stay high. If the high-time of the input signal had been less than the time needed to reach the decode (five clock pulses) the output of gate 64 would remain high and the output signal on line 26 would remain low. Therefore, any positive-going noise, like pulse 114 of FIG. 3, would not be passed to the output while the filter is enabled. Further, if the input signal went low before the decode time has elapsed (no valid high-time) the flip-flops are reset to zero count and remain reset until the input signal subsequently goes high.

The operation of flip-flops 78-80 and associated circuitry will now be described, assuming again that engine speed is below 2000 rpm. When the output on line 26 is high, any negative transition in the input signal on line 22 will cause the output to go low. This low going transition on the output will clock the flip-flop 102 to a high state which in turn maintains the output of gate 104 in a low state. The Q output of flip-flop 102 on line 107 will remain high until a valid low is seen.

When the QB output of flip-flop 102 on line 103 is low and the input signal on line 22 is low, the flip-flops 78-80 will be clocked by the clock pulses from clock 41 via lines 36 and 95 and inverter 94. The flip-flops can be clocked because then R terminals are low. Decode line 81 will stay low until transistors 83-85 have all been biased nonconductive. This occurs when the three stage ripple counter, comprised of flip-flops 78-80, has counted up to a preset count magnitude of four clock pulses. When this preset count magnitude has been counted, a decode has been reached and decode line 81 then goes from a low state to a high state. When line 81 goes high, the output of gate 96 will go low and the output of gate 100 will go high, resetting flip-flop 102. The output on line 26 will then be allowed to go high the next time a valid high is seen.

From the foregoing it can be seen that flip-flops 48-52 and associated circuitry operates as a timer which causes a decode line to change its state (low to high) whenever a predetermined time period has elapsed. The same is true of flip-flops 78-80 which also operate as a timer. In the case of flip-flops 48-52, the predetermined time period corresponds to five clock pulses and in the case of flip-flops 78-80, the predetermined time period corresponds to four clock pulses. Further, flip-flops 48-52 determine the high time duration of time and flip-flops 78-80 determine the low time duration of time. Putting it another way, flip-flops 48-52 preset the valid high time and flip-flops 78-80 preset the valid low time.

If the input signal on line 22 goes high at any time before a valid low is seen, the flip-flops 78-80 will be reset. These flip-flops will then start counting again from zero as soon as the signal on line 22 goes low again. Until a decode count is reached with the signal on line 22 low, the signal on output line 26 will be held low by flip-flop 102. Therefore, any negative-going noise on the input will be acted upon but until a valid low is seen, no further high or low transitions will occur at output line 26.

The operation of the system, when engine speed is between 2000 rpm and 4000 rpm, is generally the same as that described for operation below 2000 rpm. However, with engine speed between 2000 and 4000 rpm, all four decode lines 60, 62, 81 and 82 are enabled. Flip-flops 48-52 are so connected that a decode for line 62 will occur after two clock pulses have been counted. Flip-flops 78-80 are so connected that a decode for line 82 will occur after three clock pulses have been counted. It therefore can be seen that a decode signal will be developed on line 62 (two clock pulses) before a decode signal is developed on line 60 (five clock pulses). Further, a decode signal will be developed on line 82 (three clock pulses) before a decode signal is developed on line 81 (four clock pulses). It therefore can be seen that when engine speed is between 2000 rpm and 4000 rpm, both the valid high time and valid low time has been decreased as compared to operation below 2000 rpm. The valid high time has been decreased from a time corresponding to five clock pulses to a time corresponding to two clock pulses. The valid low time has been decreased from a time corresponding to four clock pulses to a time corresponding to three clock pulses.

The system of this invention, as has been described, uses two timers or counters provided respectively by flip-flops 48-52 and 78-80. The advantage of this arrangement is that the decode times of the two timers can be different. This allows the decode times to be selected so that they can accommodate the particular waveform of the input signal. In this regard, it is pointed out that the system disclosed in the above-referenced patent application Serial No. 65,956, uses only one timer or counter so that the high time decode time and the low time decode time must be the same.

It has been previously pointed out that line 56 is a power-on reset line. When the circuitry is powered-up the line 56 is held low by circuitry which has not been illustrated. This resets the seven flip-flops that are used in the circuit of FIG. 2. The line 56 is then brought high and it stays high until another power-up sequence is needed.

The line 92 is a test input line and it is held low during operation of the system. When it is desired to test the circuit of FIG. 2, the line 92 is brought to a high level. The circuit can then be stepped through its sequential counting and logic switching as the clock pulses from clock 41 are applied to the circuit. The clock pulses can be terminated or stopped to freeze the logic in a desired state.

At the expense of some reiteration, the following summarizes the operation of the synchronous digital filter shown in FIG. 2.

1. A positive going input signal on input line 22, with less than a predetermined high-time duration, will be ignored and accordingly will not be passed to output line 26.

2. A negative going input signal on input line 22, that has been preceded by a valid high-time duration signal on line 22, will be acted upon with the output signal on line 26 going low but no further input changes on input line 22 will be recognized until a valid, predetermined low-time has occurred.

As previously mentioned, the digital filter is a synchronous digital filter and as such only the system clock 41 is used to generate timing events. Thus, the control logic circuit is driven by flip-flops or timers 48-52 and 78-80 which in turn are clocked by clock 41. Further, the system of this invention does not use any circuit elements that provide delay paths such as the one-shot multivibrators 44 and 47 that are used in the asynchronous system disclosed in the above-referenced patent application.

Claims (4)

The embodiments of the invention in which an exclusive property or privilege is claimed are defined as follows:

1. A digital system for providing a series of voltage pulses that occur at predetermined angular connections of a crankshaft of an internal combustion engine comprising, sensor means including means driven by said crankshaft for developing a square wave signal that has a plurality of high level pulses that occur at predetermined angular positions of the crankshaft separated by low level periods, the spacing between corresponding edges of said pulses corresponding to a predetermined amount of angular rotation of said crankshaft, synchronous digital filter means having an input coupled to said sensor means and an output, said digital filter means comprising a first pulse counter for determining whether or not the time periods of said high level pulses exceed first predetermined time periods and a second pulse counter for determining whether or not the time periods of said low level periods exceed second predetermined time periods, means coupled to said counters for preventing a high level voltage pulse of said square wave signal from being passed to said output when said high level voltage pulse has a time period that was determined to be less than said first predetermined time period, means coupled to said counters for passing a high to low level transition of said square wave to said output when just prior to said transition said square wave had a high level period that was longer than said first predetermined time period, and means coupled to said counters for preventing an input transition from being passed to said output when a high to low level transition has occurred and a subsequent input transition occurs at a duration of time after the high to low transition occurred that is less than said second predetermined time period.

2. The digital system according to claim 1 where both pulse counters are connected to a source of constant frequency clock pulses.

3. The digital system according to claim 1 where said first and second predetermined time periods are not the same.

4. The digital system according to claim 1 where said first pulse counter is coupled to a first decode line and said second pulse counter is coupled to a second decode line and wherein signals are developed on said decode lines when a respective counter counts-up to a predetermined count magnitude.


1
1000
86
250 2
251 2
252 4
253 4
254 3
255 1
256 1
258 1
259 3
260 1
261 1
262 2
263 2
266 1
267 2
268 1
269 2
271 2
272 2
273 2
274 1
275 2
276 1
282 2
283 1
287 1
288 1
290 1
292 1
294 1
295 1
298 3
299 1
301 1
302 1
303 1
307 1
313 1
314 1
315 1
320 1
325 1
329 1
333 1
336 1
347 1
350 3
351 1
352 1
355 1
356 2
357 2
361 1
362 1
363 2
366 5
370 1
372 1
376 1
395 1
397 1
400 1
405 1
407 1
410 1
412 1
414 1
419 1
420 1
430 1
434 1
439 1
444 1
445 2
446 1
450 1
466 1
470 1
472 1
473 1
474 1
478 1
480 1
485 1
495 1
497 2


WHO Reports 7 New H7N9 Cases In China

Jan 10, 2014

The WHO on Thursday reported seven additional cases of H7N9 avian influenza in China.

Reuters: WHO says China has seven more cases of new H7N9 bird flu
“Seven more people in China have been found to be infected with a potentially deadly new strain of bird flu in the past week, bringing total H7N9 cases so far to around 150, the World Health Organization (WHO) said on Thursday. Six of the seven people are in a critical condition in hospitals in various parts of China and the seventh is also hospitalized but in a stable condition…” (Kelland, 1/9).

WHO: Human infection with avian influenza A(H7N9) virus — update
“…The source of infection is still under investigation. So far, there is no evidence of sustained human-to-human transmission…” (1/9).