✍ diale.org

Webpage of Tiago Charters de Azevedo

Início/Start Arquivo/Archive AdNauseum DDR


Prótese de uma mão 3D impressa

... primeira tentativa na impressão.

2018/05/25-12:51:59

Comecei hoje, já vos conto daqui a 10 hora como correu, a impressão 3D de uma mão prostética. Há muitos projectos por aí mas este Raptor Hand pareceu-me uma das melhores iniciativas.

É difícil não ficar emocionado com estes testemunhos.

Vamos ver como corre a impressão!

Impressão ficou fantástica... vamos lá montar isto!

Etiquetas/Tags: 3dprint, prosthetic, hand, mão

Filtro Kalman 1D

... implementação simples de um filtro de Kalman usando Arduino (ou outra coisa qualquer)

2018/05/19-09:25:11

Em 1960, num artigo1 que agora já é famoso, Rudolf Kalman construiu um filtro que consiste em minimizar a variância (de variáveis aleatórias gaussianas) associada a uma previsão através de um algoritmo definido por recorrência: obter uma nova estimativa usando a anterior adicionando um termo de correcção proporcional ao erro de previsão. Simples, não?

A ideia deste texto é explicar de uma forma simples a implementação de um filtro de Kalman num Arduino e construir um sensor de intensidade luminosa usando um LDR. O hardware necessário é o seguinte:

Hardware e código inicial

É fácil de encontrar um código exemplo para se ligar um LDR ao Arduino. Fica aqui uma versão simples ;)

int sensorPin = A0; 
int sensorValue = 0;

void setup(){ 
  Serial.begin(9600); 
} 

void loop(){ 
  sensorValue = analogRead(sensorPin); 
  Serial.println(sensorValue); 
} 

O gráfico seguinte mostra a variação da luminosidade quando tapo e destapo o LDR com a mão. Vê-se claramente as oscilações de 50Hz da rede eléctrica na luz do candeeiro.

Filtro de Kalman 1D

Quero então estimar o valor da luminosidade da sala onde me encontro. Para isso admito que a intensidade luminosa é constante (ou antes que necessita de ser "quase" constante de modo a que seja possível fazer uma medição) e que o valor medido y possa ser decomposto na soma de um valor médio m mais um termo de flutuação gaussiano v com variância r (valor inicial). Assim

y:=m+v

Admito também que para cada valor da luminosidade se tem a estimativa x dada por

x:=m+w

com o mesmo valor médio e flutuações gaussianas mas com variância q (valor inicial). Note-se que w e v são variáveis aleatórias gaussianas com média zero e independentes.

O filtro de Kalman admite que as sucessivas aproximações (modelo) são obtidas linearmente das anteriores, i.e. xf:=a xi . Como estou a admitir que os sucessivos valores da luminosidade são constantes ponho a:=1

x:=x

e

p:=p+q

onde p é variância da aproximação seguinte (são todas variáveis gaussianas independentes, a variância da soma é a soma das variâncias).

Ficam assim estabelecidas as regras de evolução da primeira parte do algoritmo de Kalman. Vamos à segunda parte. Esta segunda parte corresponde a estimar/prever a aproximação seguinte que é escrita em termos da aproximação anterior e o erro de previsão, i.e.,

x:=x+k(y-x)

onde k é um parâmetro a determinar, usualmente chamado de ganho do filtro, e y-x o erro de previsão. Como determinar então o valor de k? O valor de k é determinado de forma a minimizar a variância da nova estimativa x+k(y-x).

Calculando a variância desta última quantidade obtém-se

p:=(1-k)^2*p+k^2*r

É condição necessária para que se tenha um extremo relativo da variância que a derivada de p em ordem a k seja zero. Isto dá:

k:=p/(p+r)

e

p:=p*r/(p+r)

Curiosamente, ou talvez não, esta última fórmula corresponde formalmente ao valor do paralelo de duas resistências com valores p e r.

Fico assim com as duas últimas fórmulas que precisava:

k:=p/(p+r)
x:=x+k(y-x)
p:=(1-k)*p

O gráfico seguinte mostra o que acontece quando tapo e destapo o LDR (linha azul) numa escala de 0-1023. As linhas a verde e vermelho correspondem à implementação de filtros de Kalman com parâmetros diferentes.

Happy hacking!


/* Simply implementation of a 1D Kalman filter */
/* for Arduino using a LDR. */

/* Some other examples can be done with this file, */
/* e.g. sonar, temperature measurements, sky is the limit. */
/* Happy hacking! */
  
/* Author: Tiago Charters de Azevedo  */
/* Maintainer: Tiago Charters de Azevedo  */
/* URL: http://diale.org/ */
/* Version: 0 */

/* Copyright (c) - 2018 Tiago Charters de Azevedo */

/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3, or (at your option) */
/* any later version. */

/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the */
/* GNU General Public License for more details. */

/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 51 Franklin Street, Fifth Floor, */
/* Boston, MA 02110-1301, USA. */

/* Commentary: */

int sensorPin = A0; 
int sensorValue = 0;

// 1st filter parameters
float q=0.125;
float r=32;
float p=1023;
float x=0;
float k=0;

// 2nd filter parameters
float q1=4;
float r1=100;
float p1=1023;
float x1=0;
float k1=0;

void setup(){ 
  Serial.begin(9600); 
} 

void loop(){ 
  sensorValue = analogRead(sensorPin); // read sensor value

  // 1st Kalman filter
  p=p+q; 
  k=p/(p+r);
  x=x+k*(float(sensorValue)-x);
  p=(1-k)*p;

  // 2nd Kalman filter
  p1=p1+q1; 
  k1=p1/(p1+r1);
  x1=x1+k1*(float(sensorValue)-x1);
  p1=(1-k1)*p1;

  
  //Print values
  Serial.print(sensorValue); // raw value
  Serial.print(", ");
  Serial.print(int(x)); // 1st filter output
  Serial.print(", ");
  Serial.print(int(x1)); // 2nd filter output
  Serial.println("");
} 

1.R. Kalmam, A New Approach to Linear Filtering and Prediction Problems, Transactions of the ASME–Journal of Basic Engineering, 82 (Series D): 35-45. 1960

Etiquetas/Tags: kalman, arduino, filtro

Paradroid: how I did it

Steps to build a 2.5D Paradroid for 3D printing

2018/05/18-10:29:14

It all started when I found some drawings of the character of the infamous computer game from the 80's.

The next step was obvious to me, just build a raster graphics of the beast using GNU/Octave. As is the original image needed some modification on order to be 3d-printed.

A=[1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1;
1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1;
1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1;    
1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1;
1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1;
1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1;    
1 1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 0 1;
1 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 1 0 0 0;
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0;
0 0 1 1 1 0 0 1 0 0 1 1 1 0 0 1 1 1 0 0 0;
0 0 1 1 1 0 0 1 0 0 1 1 1 0 0 1 1 1 0 0 0;
0 0 1 1 1 0 0 1 0 0 1 1 1 0 0 1 1 1 0 0 0;
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 1 0 0 0;
1 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 1 0 0 0;    
1 1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 0 1;
1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1;
1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1;    
1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1];
imshow(A)

print -deps -color paradroid.eps
print -dpng -color paradroid.png

So added some extra squares to get the job done.

Then used the Inkscape-to-OpenSCAD plugin and got the final 3d model, after some editing on the output code.

And it prints nicely with a resolution of 0.2mm and a 20% infill.

You can get it here: https://www.youmagine.com/designs/paradroid-ornament-key-chain

Share and enjoy!

Etiquetas/Tags: paradroid, 3d, 3dprinting, 3dprint, game, math

Berry's paradox and elegant LISP programs

in Common Lisp

2018/05/18-10:29:07

Giro!

(defun s-expressin-length (s)
  (length (write-to-string s)))

(defun complexity (s)
  (s-expressin-length (eval s)))

(complexity  '(car '(a b)))  

(defun is-elegant (s)
  (cond ((eq (s-expressin-length s) (complexity s))
         t)
        (t
         nil)))

(defun berry1 (lst)
  (cond ((null lst) nil)
        (t
         (cond ((and (is-elegant lst) 
                     (>= (complexity lst) (s-expressin-length #'berry1)))
                #'berry1)
               (t
                lst)))))

(defun berry (lst)
  (cond ((null lst) nil)
        (t
         (cond ((and (is-elegant (car lst)) 
                     (>= (complexity (car lst)) (s-expressin-length #'berry))))
                #'berry)
               (t
                (berry (cdr lst))))))


Alguns extras úteis que tinha para aqui.

As notas aqui descritas estão pensadas para SBCL - Steel Bank Common Lisp em Debian - GNU/Linux.

  1. Pedir a CL para não gritar (inlcuir a instrução no ficheiro ~/.sbclrc):
(setf *print-case* :downcase)
  1. A maneira mais simples de instalar e manter os packages em CL é usando o ASDF. Há dois manuais que valem a pena ser lidos:
  2. Exemplo de instalação usando o asdf: Para instalar a LTK - The Lisp Toolkit faz-se:
(require 'asdf-install)
(asdf-install:install 'ltk)
O asdf faz o download dos ficheiros e diz
Downloading 240780 bytes from http://www.peter-herth.de/ltk/ltk-0.91.tgz ...
e pergunta:
Install where?
1) System-wide install: 
   System in /usr/lib/sbcl/site-systems/
   Files in /usr/lib/sbcl/site/ 
2) Personal installation: 
   System in /home/tca/.sbcl/systems/
   Files in /home/tca/.sbcl/site/ 
respondo 2.

Etiquetas/Tags: LISP, Berry paradox

A verdade, nada mais do que a verdade

Notas sobre o Teorema de Godel (exposição informal)

2018/03/18-00:17:02

Vamos construir uma máquina de calcular que escreve expressões compostas pelos seguintes símbolos neg P N ( ).

Por expressão entenda-se uma lista não vazia composta por estes cinco símbolos. Uma expressão X é "printável"1 se a máquina a conseguir escrever ("printar"). Admitimos que a máquina está programada de a modo a escrever expressões que pode imprimir, i.e., gasta todo o seu tempo a imprimir expressões.

Chama-se norma de uma expressão X à expressão composta X(X); por exemplo, a norma de P neg é P neg (P neg). Uma frase válida tem uma das seguintes formas:

  1. P(X)
  2. P N(X)
  3. neg P(X)
  4. neg P N(X)

Se associarmos, informalmente, a três dos símbolos anteriores um significado podemos ler uma qualquer frase válida. Assim associamos os seguintes significados a P, N e neg:

Com esta interpretação podemos dizer que P(X) é uma frase verdadeira se, e só se, X é printável1; do mesmo modo PN(X) é verdadeira se, e só se, a norma de X poder ser escrita, neg P (X) é verdadeira sse2 X não poder ser escrita e neg P N(X) é verdadeira se a norma de X não poder ser escrita. Assim as definições anteriores permitem-nos falar em português, e com rigor, sobre o que afirmam cada uma das frases escritas pela máquina e o que significa uma expressão verdadeira. Estas são de facto, auto-afirmações, efectuadas pela máquina, são frases que nos dizem algo sobre a máquina que as escreve. A máquina durante o seu funcionamento descreve o seu próprio funcionamento, semelhante a um organismo consciente.

Assim concluímos que a máquina está bem definida, i.e., funciona bem, e que todas as frases que por ela são escritas são expressões verdadeiras. Por exemplo, se a máquina escrever P(X), isto significa que X pode ser realmente escrito (X será escrito mais tarde ou mais cedo); da mesma forma se num instante posterior a máquina escrever P N(X) então X(X) também aparecerá mais tarde. Admitamos agora que X pode ser escrito pela máquina, será que podemos concluir que P(X) também o será? Se X pode ser escrito pela máquina então a frase P(X) é verdadeira, mas não sabemos, de facto, se P(X) pode ser escrito pela máquina, ou seja, se P(P(X)) é verdadeira.

Será possível a máquina escrever todas as afirmações verdadeira que falam sobre ela?

A resposta a esta pergunta é, um surpreendentemente, não! Para podermos verificar isso temos que encontrar uma frase que seja verdadeira, i.e., que afirme algo verdadeiro sobre a máquina, e que a máquina não consiga escrever. Basta construir uma frase, uma expressão, que afirme a sua não "printabilidade".

Uma candidata seria: Esta frase "esta frase não pode ser escrita" não pode ser escrita. Ou seja neg P N (neg P N), que afirma que a norma de neg P N não pode ser escrita. Por definição de expressão verdadeira, a frase anterior é verdadeira se a norma de neg P N não pode ser escrita, mas a norma de neg P N é exactamente a frase neg P N (neg P N)!

Algumas frases apressadas

Ref: Smullyan, R M (2001) "Gödel's Incompleteness Theorems" in Goble, Lou, ed., The Blackwell Guide to Philosophical Logic. Blackwell

1. Vou usar "printável" para dizer o mesmo que "pode ser escrita".

2. sse = se, e só se

Etiquetas/Tags: Godel, teorema, notas, Smullyan

Word list

Funções em elisp para manipulação de ficheiros de palavras.

2018/03/18-00:17:02

Na antiga versão do jogo do monopólio existia uma carta da sorte que começava com a expressão "Levou um tiro de um amigo..." e normalmente o que se seguia consistia no pagamento de uma conta do hospital.

Um amigo não me deu um tiro mas fez-me uma pergunta, e no meu caso a procura da resposta leva a quase uma visita ao hospital. A pergunta era: " Será que existem palavras de 5 letras em português que verifiquem o padrão seguinte?"

1 5 9 1 7 
2 6 0 5 6 
3 7 3 4 0 
4 8 2 8 9 
Nota: cada número representa uma letra diferente.

Não interessa muito de onde aparece a motivação da pergunta, interessa-me mais a procura da resposta. Há largos meses que tinha começado a ler o volume 4 do TAOCP Combinatorial Algorithms, Part 1 onde, entre outras coisas, é usada a Stanford GraphBase, uma lista de 5757 palavras em inglês com cinco letras, para exposição dos vários algoritmos que aí são descritos.

Propus-me então replicar1 alguns dos resultados descritos no TAOCP usando palavras em PT. Para isso precisava de um dicionário e uma maneira de começar a extrair a informação. O resultado é este pequeno conjunto de funções em elisp. Muito ainda está por fazer, por exemplo, o aspell usa um sistema de compressão para prefixos e sufixos, cuja sintaxe só descobri hoje, e que aumenta o número de palavras disponíveis para se brincar.

;;; wlist.el --- Emacs tools for manipulating word-files 
;; word-files, meaning a file with words in it, one word per line.

;; Author: Tiago Charters de Azevedo <tca@diale.org>
;; Maintainer: Tiago Charters de Azevedo <tca@diale.org>
;; Created: Fev, 17, 2012
;; Version: .1
;; Keywords: words
;; URL: http://diale.org/wlist.html

;; Copyright (c) 2012 Tiago Charters de Azevedo

;; This file is not part of GNU Emacs.

;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.

;;; Commentary:
;; None.

;; Code:

(defvar wlist-max-lenght 
  0
  "")

(defvar wlist-regexp-pt
  "[aerisontcdmlupvgbfzáhçqjíxãóéêâúõACMPSBTELGRIFVDkHJONôywUKXZWQÁYÍÉàÓèÂÚ].+"
  "Regular expression for a portuguese word; see aspell.")

(defun wlist-looking-at-size ()
  "Returns the length of a word on the beginning of a line (pt-PT)."
  (interactive)
  (if  (looking-at wlist-regexp-pt)
      (length (match-string-no-properties 0))
    0))

(defun  wlist-looking-at-size-plus-1 ()
  (interactive)
  (forward-line 1)
  (wlist-looking-at-size))

(defun wlist (size)
  "Removes all sized SIZE words from `current-buffer'; asks SIZE."
  (interactive "n") 
  (with-current-buffer (current-buffer)
    (goto-char (point-min))
    (save-excursion  
      (while (< (line-number-at-pos) (line-number-at-pos (point-max)))
        (when (not (= size (wlist-looking-at-size)))
          (delete-region (point) (line-end-position)))
        (forward-line 1))))
  (wlist-delete-blank-lines))

(defun wlist-delete-blank-lines ()
  (interactive)
  (with-current-buffer (current-buffer)
    (goto-char (point-min))
    (save-excursion  
      (while (< (line-number-at-pos) (line-number-at-pos (point-max)))
        (delete-blank-lines)
        (forward-line 1)))))

(defun wlist-insert-header ()
  "Inserts a not so beautiful header."
  (goto-char (point-min))
  (insert (format "File name: %s\n" (file-name-nondirectory (buffer-file-name)))
          (format "Number of %s sized words: %s\n" size (line-number-at-pos (point-max)))))

(defun wlist-hamming-dist-list (lst1 lst2)
   "For equal length lists is the number of positions at which the 
corresponding lists are different."
  (if  (and lst1 lst2
            (= (length lst1) (length lst2)))
      (if (equal (car lst1) (car lst2))
          (wlist-hamming-dist-list (cdr lst1) (cdr lst2))
        (+ 1 (wlist-hamming-dist-list (cdr lst1) (cdr lst2))))
    0))

(defun wlist-hamming-dist (str1 str2)
  "For equal length strings is the number of positions at which the 
corresponding strings are different."
  (wlist-hamming-dist-list (string-to-list str1) 
                              (string-to-list str2)))

(defun wlist-remove-bslash ()
  "Remove /* properties form word-file. No plurals or m/f, etc,... 
Needs to be changed correctly for portuguese."
  (interactive)
  (with-current-buffer (current-buffer)
    (goto-char (point-min))
    (save-excursion  
      (while (search-forward-regexp "\\(.+\\)\\(/.+\\)" nil t)
        (let ((word-s (match-string-no-properties 1)))
          (replace-match word-s))))))

(defun wlist-max-size ()
  "Gets the maximum size of all words in a word-file."
  (interactive)
  (with-current-buffer (current-buffer) 
    (goto-char (point-min))
    (save-excursion  
      (while (< (line-number-at-pos) (line-number-at-pos (point-max)))
        (setq wlist-max-lenght (max (wlist-looking-at-size) (wlist-looking-at-size-plus-1) wlist-max-lenght))))))

(defun wlist-file-size (size)
  "Determines and creates a file of all the words with size SIZE."
  (interactive "n")
  (let ((dic-words (buffer-string)))
    (with-temp-buffer
      (insert dic-words)
      (wlist size)
      (append-to-file (point-min) (point-max) 
                      (concat default-directory (format "%s.wl" size))))))

(defun wlist-all-files-sizes ()
  "Determines all the words from size 2 to `wlist-max-size' 
and save them to separate files *.wl; it takes a few minutes to finish."
  (interactive)
  (if (= wlist-max-lenght 0)
      (wlist-max-size))
  (let ((size 2))
    (while (<= size wlist-max-lenght )
      (wlist-file-size size)
      (incf size))))
  
(defun wlist-same-pos (n)
  (interactive "x")
  (with-current-buffer (current-buffer) 
    (goto-char (point-min))
    (save-excursion  
      (while (< (line-number-at-pos) (line-number-at-pos (point-max)))
        (looking-at wlist-regexp-pt)
        (if (not (equal (nth (- (car n) 1 )
                        (string-to-list (match-string-no-properties 0)))
                   (nth (- (cadr n) 1)
                        (string-to-list (match-string-no-properties 0)))))
;;          (message (match-string-no-properties 0)))
            (delete-region (point) (line-end-position)))
        (forward-line 1)))
    (wlist-delete-blank-lines)))

(defun wlist-file-same-pos (n)
  (interactive "x")
  (let ((i (car n))
        (j (cadr n))
        (words (buffer-string)))
    (with-temp-buffer
      (insert words)
      (wlist-same-pos (list i j))
      (append-to-file (point-min) (point-max) 
                      (concat default-directory (format "%s_%s.wl" i j))))))


(defun wlist-find-all-hamming-dist-word (word dist)
  (with-current-buffer (current-buffer) 
    (goto-char (point-min))
    (save-excursion  
      (while (< (line-number-at-pos) (line-number-at-pos (point-max)))
        (looking-at wlist-regexp-pt)
        (if (not (= dist (wlist-hamming-dist word (match-string-no-properties 0))))
            (delete-region (point) (line-end-position)))
        (forward-line 1)))
    (wlist-delete-blank-lines)))

(defvar wlist-buffer-content-list nil
  "")

(defun wlist-buffer-length ()
  (count-lines (point-min) (point-max)))
  
(defun wlist-buffer-alist ()
  (interactive)
  (with-current-buffer (current-buffer) 
    (goto-char (point-min))
    (let ((wl-buffer-list nil))
      (save-excursion  
        (while (< (line-number-at-pos) (line-number-at-pos (point-max)))
          (looking-at wlist-regexp-pt)
          ;;    (push 'new-item accumulator)
        (push (match-string-no-properties 0) wl-buffer-list)
        (forward-line 1)))
      (reverse wl-buffer-list))))

(defvar wlist-word-link nil
  "")

(defun wlist-hamming-dist-word-insert (word dist)
  "Looks for the hamming DIST of word WORD, inserts all the words found after WORD."
  (setq wlist-word-link nil)
  (with-current-buffer (current-buffer) 
    (goto-char (point-min))
    (save-excursion
      (while (< (line-number-at-pos) (line-number-at-pos (point-max)))
        (looking-at wlist-regexp-pt)
        ;; Looks for word in file and save point, for inserting.
        (if (equal word (match-string-no-properties 0))
            (setq w-point (list (point) (line-end-position))))
        (forward-line 1)))
    (save-excursion  
      (while (< (line-number-at-pos) (line-number-at-pos (point-max)))
        (looking-at wlist-regexp-pt)
        (if (= dist (wlist-hamming-dist word (match-string-no-properties 0)))
            (push (match-string-no-properties 0) wlist-word-link))
        (forward-line 1)))
    (goto-char (cadr w-point))
    (insert (format " %s" (mapconcat 'concat word-link " ")))))

(defun wlist-hamming-dist-insert-buffer (dist)
  "Builds the world link with DIST and inserts the result after every word in buffer."
  (let ((wlist-list (wlist-buffer-alist)  ))
    (dolist (word wlist-list)
      (wlist-hamming-dist-word-insert word dist))))

(defun wlist-insert-after-word (word in-word)
  "Insert IN-WORD in `curren-buffer' after WORD."
  (with-current-buffer (current-buffer) 
    (goto-char (point-min))
    (save-excursion
      (while (< (line-number-at-pos) (line-number-at-pos (point-max)))
        (looking-at wlist-regexp-pt)
        (if (equal word (match-string-no-properties 0))
            (replace-match (format "%s %s" word in-word)))
        (forward-line 1)))))

(defun wlist-hamming-dist-word-list (word dist)
  "Looks for the words with hamming DIST of word WORD; returns all of the in a list."
  (setq wlist-word-link nil)
  (with-current-buffer (current-buffer) 
    (goto-char (point-min))
    (save-excursion  
      (while (< (line-number-at-pos) (line-number-at-pos (point-max)))
        (looking-at wlist-regexp-pt)
        (if (= dist (wlist-hamming-dist word (match-string-no-properties 0)))
            (push (match-string-no-properties 0) wlist-word-link))
        (forward-line 1))))
  (reverse wlist-word-link))

(defun wlist-word-link-next (word dist)
  "Returns the next link of word-link with hamming DIST of word WORD."
  (car (wlist-hamming-dist-word-list word dist)))

(defun wlist-one-word-link (word dist n)
  "Returns a word-link from WORD whit hamming distance DIST."
  (let ((word-link word)
        (new-word (wlist-word-link-next word dist)))
    (while (and new-word (<= 0 n))
      (push new-word word-link)
      (wlist-one-word-link new-word dist (- n 1)))))
            
(provide 'wlist)


1. Existe tamanho palavrão em português?.

Etiquetas/Tags: aspell, emacs, elisp

Teaser for my new guitar amplifier

1/4W to 3W class a mosfet amplifier

2018/03/18-00:17:02

Here is my new class A mosfet amplifier 1/4W to 3W guitar amp.

More pics and sound samples later.

Etiquetas/Tags: DIY, guitar, amplifier

WAMP - 1 W guitar amplifier

A simple two stage mosfet class a guitar amplifier

2018/03/18-00:17:02

Sounds much better than any chip amp, overdrives nicely with a booster in front of it. Sounds clean with good compression, high output impedance, can drive 8/16Ohms cabs (even 4Ohm).

Some oscilloscope pics:

Have fun!

Etiquetas/Tags: class a, mosfet, guitar, amplifier, diy

Wharfedale 15 woofer

... que tenho aqui em casa

2018/03/18-00:17:02

Finalmente consegui descobrir qual o altifalante que tinha aqui para casa (era do meu avô): um Wharfedale de 15 polegadas. Precisa de um restauro mas o cone e a spider parecem estar em boas condições!

Etiquetas/Tags: Wharfedale, 15'', woofer, W15/cs

Nova descobertta - chemoton

Blog de vitorino ramos

2018/03/18-00:17:02

O muito saudoso VRamos da a-formiga-de-langton.blogspot.com está agora aqui: http://chemoton.wordpress.com

P.S.

Só agora, passados estes anos, é que reparei que ao meu antigo blog (abundantetempolivre) foi atribuído dois dos prémios Formiga:

Bons tempos esses de 2003!

Etiquetas/Tags: blog, VRamos

Palavras chave/keywords: página pessoal, blog

Criado/Created: NaN

Última actualização/Last updated: 25-05-2018 [12:52]


GNU/Emacs Creative Commons License

(c) Tiago Charters de Azevedo