Incontri spaziali: la congiunzione tra Giove e Saturno (21/12/2020)

Incontri spaziali. Sembra che Giove e Saturno siano prossimi a scontrarsi ma naturalmente è solo una questione di prospettiva: è la loro proiezione sulla volta celeste a farlo.

Quello che accade realmente è che siamo all’incirca tutti e tre, noi, Giove e Saturno, lungo un’unica linea retta di congiunzione.

Incontri spaziali: Giove e Saturno si incontrano sulla sfera celeste sotto un angolo di 1/5 del disco lunare
Giove e Saturno si incontrano sulla sfera celeste sotto un angolo di 1/5 del disco lunare

Non si tratta in realtà di un allineamento perfetto; più precisamente vediamo entrambi i pianeti sotto un angolo solido pari a circa di 1/5 del disco lunare.

Per esempio questa elaborazione della Nasa mostra cosa si intenda per allineamento tra pianeti. Quello qui rappresentato è la sovrapposizione tra Venere e Giove avvenuta il 30 giugno 2015

Allineamento tra Terra, Venere e Giove del 30 giugno 2015
Allineamento tra Terra, Venere e Giove del 30 giugno 2015

Questo delle congiunzioni o allineamenti è un evento molto raro sulla scala di una vita umana. L’ultima volta che Giove e Saturno si trovarono così vicini sulla volta celeste successe 4 marzo 1226. In quell’anno morirono S. Francesco d’Assisi e Federico II di Hohenstaufen.

Non per la congiunzione astrale, beninteso, è solo una coincidenza!

Anche un’altra volta avvenne, il 16 luglio 1623, però da terra non si vide nulla perché la congiunzione avvenne vicino al disco solare, verso il tramonto.

La congiunzione tra Giove e Saturno in realtà avviene molto più spesso, circa ogni 20 anni, ma non sempre entro un angolo così piccolo e in condizione di oscurità favorevole. Una lista delle congiunzioni tra i due pianeti, nel passato e nel futuro si trova in questa risorsa. Trovate tutte le congiunzioni, più o meno notevoli, dei due pianti dal 1206 al 2398.

Appunto, l’ultima volta i cui entrambe queste condizioni si verificarono, fu nel 1226.

C’è da dire che questa è la prima volta in assoluto che noi umani possiamo goderci lo spettacolo così da vicino, grazie alla Scienza e alla Tecnologia.

Qui trovate l’evento raccontato su The Virtual Telescope Project da Gianluca Masi.

Fonti

PKIX: errore nel creare un’applicazione Grails.

PKIX: La non disponibiità di un certificato SSL è all'origine del problema
La non disponibiità di un certificato SSL è all’origine del “problema PXIX”

PKIX: una precisazione

Voglio avvisarvi subito che non esiste in sé un “errore PKIX”. È soltanto un modo breve di descrivere una situazione in cui c’è un problema del client Grails (o a qualunque altro client) ad accedere ad un URL protetto da SSL.

Se vi capita di vedere questa sigla PKIX in un messaggio errore di Grails, si fa riferimento alla Public Key Infrastructure X.509, uno standard usato per definire il formato dei certificati a chiave pubblica (PKC) e delle autorità di certificazione (CA).

Significa che è sorto qualche problema nello stabilire la connessione cifrata SSL con lo storage da cui il client scarica il template dell’applicazione.

Mi è capitato in più di un contesto questo problema (ad esempio nella configurazione di un reverse proxy Apache), però il significato di un simile tipo di sintomatologia risulta abbastanza chiaro nello specifico esempio che vi propongo.

Qual è il problema per cui compare questa misteriosa sigla PKIX?

Questo problema sorge appena si avvia il client Grails:

$ grails

compare infatti il seguente messaggio di errore:

“PKIX path building failed” and “unable to find valid certification path to requested target”

Ciò che succede è che insorge un problema di sicurezza perché non ho tra i certificati SSL installati nella JVM quello di grails.org da cui il client cerca di scaricare il boilerplate dell’applicazione. Da qui l’errore PKIX.

Una soluzione

La soluzione consiste nello scaricare e installare manualmente il certificato dal sito con Chrome o Firefox, e importarlo nel keystore della JVM.

I passaggi sono un po’ diversi a seconda del browser che state usando per accedere all’applicazione Laravel, per cui per vostra comodità vi illustro i passaggi con entrambi i browser. Per i possessori di Mac: mi dispiace. Per gli appassionati di Edge / Microsoft Internet Explorer: mi dispiace.

Passaggio 1

Scaricare il certificato: puntare il browser all’URL

https://repo.grails.org/grails/core

Una volta stabilita la connessione e visualizzato il sito, cliccare sul lucchetto a sinistra nella barra degli indirizzi; cliccare quindi su “Certificato”, su “Dettagli”, su “Esporta” e fare il download in una cartella che conosciamo, ad esempio Downloads. Questo per Chrome.

Nota bene: questa è un’operazione che potete fare con qualunque sito in https, potete così informarvi sull’autorità emittente, sul proprietario del sito, sull’attendibilità e la validità del certificato di chiave pubblica.

Per Firefox: cliccare sul lucchetto, quindi su “Connessione Sicura >”, su “Ulteriori informazioni”, su “Visualizza certificato”; quindi sulla tab repo.grails.org cliccare sul link “PEM (certficato) e selezionare l’opzione “Salva con nome”. Un po’ più laborioso.

Passaggio 2

Importare il certificato appena scaricato nella keystore della JVM: individuare dunque la directory della JVM, nel mio caso:

/usr/lib/java/jdk1.8.0_25/jre/lib/security

Il file dei certificati è cacerts

Lanciare l’importazione

$ sudo keytool -import -alias example 
   -keystore /usr/lib/java/jdk1.8.0_25/jre/lib/security/cacerts 
   -file /home/marcob/Downloads/repo.grails.org 

Keytools richiede la password del keystore che al primo utilizzo è changeit

[sudo] password di marcob: 
Immettere la password del keystore:  

Proprietario: CN=repo.grails.org
Emittente: CN=Sectigo RSA Domain Validation Secure Server CA, O=Sectigo Limited, L=Salford, ST=Greater Manchester, C=GB
Numero di serie: 2560fb52bfdc8f6bb2b3366805e3c911
Valido da: Fri Nov 13 01:00:00 CET 2020 a: Wed Dec 15 00:59:59 CET 2021
Impronte digitali certificato:
	 SHA1: D6:24:89:09:18:F1:39:E8:D6:6F:DF:EA:88:68:5C:BD:DB:2C:DF:F3
	 SHA256: 65:39:9F:7D:C3:09:D5:58:ED:E3:C3:82:59:98:BA:22:E2:8F:2D:65:6D:1E:F6:C3:51:55:9B:4F:14:9C:ED:A4
Nome algoritmo firma: SHA256withRSA
Algoritmo di chiave pubblica oggetto: Chiave RSA a 2048 bit
Versione: 3
...
Considerare sicuro questo certificato? [no]:  si
Il certificato è stato aggiunto al keystore

Una volta completato l’nserimento del certificato nel portachiavi si può avviare Grails dalla cartella del progetto:

$ grails create-app com.djamware.gadgethouse
| Application created at /home/marcob/IdeaProjects/java/gadgethouse
| Resolving Dependencies. Please wait…
| Starting interactive mode…
| Enter a command name to run. Use TAB for completion:
grails> run-app
| Running application…
...
Grails application running at http://localhost:8080 in environment: development

Fine.

PS: ho preso l’esempio da questo sito qui

Grails in pillole – come superare i problemi che sorgono con database già fatti

Grails Logo
Grails

In questo articolo parlerò dei problemi che si incontrano nel refactoring di una applicazione. Più precisamente di quanto espresso dal titolo quindi:

Come gestire l’ORM (Object Relationship Mapping) su tabelle già definite.

Devo riscrivere un’applicazione PHP in Groovy on Grails ma il database non deve essere toccato come specifica di progetto.

Le pratiche di convention over configuration di molti framweork MVC (come Groovy on Grails, Laravel o Django) permettono di creare il database semplicemente dalla definizione delle classi, senza scrivere alcuna istruzione DDL.

Tuttavia se il Cliente non vuole che si modifichi il database, abbiamo una serie di strumenti messi a disposizone dal layer di gestione della mappatura tra oggetti e tabelle adottato da Grails (Hibernate) che ci permettono di uscire dallo standard per adeguarci all’esistente.

Importante: se non si vuole sovrascrivere il database, nel file grails-app/conf/dataSource.groovy va impostato il parametro dbCreate come “update“, non come “create-drop” (mi raccomando).

Se c’è già un campo chiave primaria

Ogni tabella ha come standard la colonna ID che di solito è un number(10) (sto usando Oracle). Se nella definizione della classe aggiungiamo la proprietà id, Hibernate mapperà il campo id nella colonna ID senza protestare.

Il campo version

Hibernate aggiunge per ogni tabella anche il campo version per implementare la strategia di “optimistic locking”. Cioè si vuole gestire una storia del record per cui viene di fatto creata una chiave composita che si riferisce ad un particolare record attraverso la fornitura sia dell’id che del numero di versione. In realtà in molte applicazioni a cui ho lavorato questo tipo di meccanismo è delegato al DBMS, nel quale (soprattutto nei database Oracle che ho gestito) viene scritto un trigger che crea un “giornale” della tabella con dentro tutte le oprazioni fatte sul record: dal primo inserimento, alle succesive modifiche fino all’eventuale cancellazione fisica. Per cui, in questo contesto ho ritenuto sovrabbondante l’introduzione dell’oprimistic locking e ho optato per la sua soppressione.

Per evitare di gestire una proprietà version si deve dichiare che non la si vuole nel dictionary mapping dentro alla dichiarazione del domain (il corrispondente Grails del model nel paradiga MVC):

package myapp
class Utente
    ...
    static mapping = {
        version false
    }

Il campo version non verrà aggiunto alla tabella.

Il nome della tabella non segue uno standard

I nomi delle classi domain e nelle tabelle prassi abbastanza diffusa sceglierli in inglese, al singolare; però io ho una tabella Utenti per cui faccio un compromesso:

package myapp
class Utente
    ...
    static mapping = {
        table "utenti"
        version false
    }

Specificando nel dictionary statico mapping il campo table posso scegliere di associare il nome della tabella del database “intoccabile”.

Relazioni uno a molti

Come esempio ho un tabella articoli che è figlia di una tabella capitoli: ad un capitolo possono essere associati più articoli. Ho di fatto una serie di articoli che appartengono ad un capitolo per cui si usa la variabile belongsTo per specifcare questa relazione:

package myapp

class Articolo {
    Integer id
    Float prezzo
    String descrizione
    Integer attivo

    static belongsTo = [capitolo: Capitolo]

In questa dichiarazione, il nome a sinistra del : è il nome della relazione (capitolo in minuscolo), e il nome a destra è il nome dell’oggetto padre (Capitolo).

Il nome delle chiavi esterne non segue uno standard

O, meglio, ne segue uno di suo che non è quello di Grails. Nella tabella Articoli per esempio ho una chiave esterna per realizzare la relazione con i Capitoli: idcapitolo che si riferisce all’id della tabella Capitoli.

Seguendo il suo standard, Hibernate crea il nome <tabella>Id per dichiarare le variabili “chiave”. Sfortunamtamente all’epoca nel database hanno seguito la convenzione inversa IDCAPITOLO (con l’id prima del nome tabella).

Mai paura: si dichiara questa deviazione dallo standard nella creazione del domain:

package myapp

class Articolo {
    Integer id
    Float prezzo
    String descrizione
    Integer attivo

    static belongsTo = [capitolo: Capitolo]
    static mapping = {
        table "articoli"
        capitolo column: "idcapitolo" // <-----
        version false
    }

Si faccia attenzione che per mappare il nome della colonna della tabella database ho utilizzato il nome della relazione definita in belongsTo: non capitoloId (che non è definito da nessuna parte) ma capitolo.

Una tabella ha una chiave primaria composita

Come ultimo caso c’è quello di una tabella con una doppia chiave composta dall’unione di due campi idutente e iddipartimento (dovendo gestire il fatto che un utente può lavorare anche in dipartimenti diversi). È una strategia per gestire una relazione molti-a-molti. Di suo Hibernate vorrebbe che io aggiungessi una chiave artificiale ID ma la consegna data me lo impedisce, posso dichiarare la chiave composita e sopprimere la direttiva di creazione dell’ID:

package myapp

class UtenteDipartimento implements Serializable {
    Integer attivo
    Date dataInizio
    Date dataFine

    static belongsTo = [utente: Utente, dipartimento: Dipartimento]
    static mapping = {
        table "utenti_dipartimenti"
        dataInizio column: "data_inizio"
        dataFine column: "data_fine"
        // relazioni
        utente column: "idutente"
        dipartimento column: "iddipartimento"
        id composite: ['utente', 'dipartimento']

        version false
    }

nel quale sorgente riassumo un po’ tutte le cose dette nell’articolo.

Attenzione: se voglio creare una chiave composita, la classe deve implementare l’interfaccia Serializable.

Risorse

Grails Framework home page

Oracle: alcuni tips utili

Oracle Logo

Oracle tips: in questo post troverete alcuni consigli utili per gestire situazioni anomale che, quindi, normamente non si dovrebbero verificare: la password di system è scaduta oppure Sql*Plus non si avvia.
Aggiungo anche un suggerimento su come creare un nuovo schema e degli utenti di supporto per limitare le operazioni sul database da applicazione.

Problem 1: password di system scaduta

Il problema si presenta tipicamente quando non si accede da molto ad un database. È un’eventualità abbastanza remota se si lavora regolarmente sui sistemi. Nel mio caso avevo un vecchio DBMS Oracle di sviluppo in una macchina Windows 10 che non usavo da un po’ ed era scaduta anche la password di system.

Una semplice procedura consente di risolvere il problema. Da linea di comando si digiti

$ sqlplus system
SQL*Plus: Release 11.2.0.2.0 Production on Mer Nov 25 11:57:12 2020
...
Enter password:
ERROR:
ORA-28001: the password has expired
Changing password for system
New password:
Retype new password:
Password changed

Stessa procedura per qualsiasi altro utente. In sostanza Oracle avvia automaticamente la procedura di cambio password nel caso sia scaduta. È chiaro che il ststema è bene non venga lasciato inattivo per troppo tempo, perché chiunque potrebbe impossessarsi del DBMS con questa procedura!

Problem 2: indisponibilità di SQL*Plus

Nel tentativo di risolvere il problema sopra, ho cozzato contro un altro problema che veniva prima in ordine di priorità, ossia non riuscivo nemmeno ad avviare SQL*Plus, il tool di amministrazione/sviluppo di Oracle da linea di comando.

SQL*Plus è uno strumento molto grezzo ma è potentissimo, consente di lanciare ogni tio di comando di amministrazione (DDL) ed elaborazione dati (SQL).

Generalmente si preferisce utilizzare tool con una GUI (Graphic User Interface) come TOAD o Oracle SQL Developer ma questo tool è davvero equivalente, se non più potente.

Nel mio caso l’errore che si verificava all’avvio del comando era il seguente:

C:\> sqlplus
PSP2-0667: Message file sp1<lang>.msb not found

Il problema all’origine di questo messaggio è la non corretta valorizzazione della variabile di ambiente ORACLE_HOME, ho impostato (nel mio caso) al valore:

ORACLE_HOME=C:\oraclexe\app\oracle\product\11.2.0\server\

Problema rientrato.

Tip 1: come creare uno schema

Ecco invece una breve lista di comandi per creare uno schema (uno schema è un utente Oracle proprietario di oggetti) e utilizzarlo per un’applicazione web (da sviluppare con qualsiasi tecnologia).

  1. CREATE USER rewards IDENTIFIED BY smartPassw0rd;
  2. GRANT CONNECT, RESOURCE TO rewards;
  3. GRANT CREATE SESSION TO rewards;
  4. CREATE USER rewards_rw IDENTIFIED BY P4ssw0rd;

Una volta creati gli oggetti, ad esempio creata una una tabella books, devo stabilire cosa l’utente può fare in questa tabella; devo concedere (GRANT) dei privilegi all’utente sulla tabella, andando dalla sua modifica, alla distruzione, alla gestione dei dati. Per questo utente mi limito alle sole operazioni CRUD:

  1. GRANT SELECT, INSERT, UPDATE, DELETE ON rewards.books TO rewards_rw;

È buona prassi non dare i massimi privilegi sul database all’utente utilizzato dall’applicativo per connettersi a Oracle mediante il client. In genere è sufficiente un profilo abilitato alle sole operazioni CRUD, come realizzato dal comando sopra.

Si evita così la possibilità che in modo malevolo (sempre che l’applicazione lo consenta – e lo consente se non è progettata abbastanza bene da inibire comandi SQL – la cosiddetta SQL injection) un attaccante, per mezzo dell’applicazione, lanci istruzione SQL verso il server Oracle.

CRUD

Un’ultima considerazione: CRUD è l’elenco delle operazioni su database definite però in un ambito più genarale e astratto di storage. In pratica queste quattro operazioni (4 verbi) sono richieste e possibili anche in un file system, per esempio: creazione, lettura, scrittura, cancellazione di file, e non è inteso specificatamente per un DBMS. Tuttavia nel linguaggio SQL le quattro operazioni prendono dei nomi specifici:

  • Create → Insert
  • Read → Select
  • Update → Update
  • Delete → Delete

Links utili

Oracle Database Administration Guide

Mysql Workbench su Ubuntu 20.04

Mysql Workbench su Ubuntu 20.04
Mysql Workbench su Ubuntu 20.04

Ho reinstallato Mysql Workbench versione Community, un tool per l’amministrazione e la gestione di database basati su DBMS MySQL/MariaDB, su Ubuntu 20.04.

Al tentativo di creare una nuova connessione mi sono ritrovato un errore mai comparso prima:

An AppArmor policy prevents this sender from sending this message to this recipient; type="method_call", sender=":1.125"

eccetera.

Il problema (spiegato qui) è che ho dovuto installare MySQL con snap anziché apt, per cui mi sono scontrato con il fatto che i pacchetti installati con snap sono sandboxed, in qualche modo isolati e non possono fare alcune richieste al sistema. Ho dovuto quindi applicare questo comando:

$ sudo snap connect mysql-workbench-community:password-manager-service :password-manager-service

Ora funziona:

Sul modulo kernel Linux Apparmor ho già dedicato questo articolo.

Se vi è servito, lasciatemi un like

Matematica: la congettura di Collatz

Congettura di Collatz
Congettura di Collatz

Congettura

Cos’è una congettura? È una proposizione che si presume vera ma non si è in grado di dimostrare rigorosamente. Le congetture affascinano perché funzionano per tutti i tentativi che si fanno per verificarla, cioè per trovare una dimostrazione di ciò che dicono. E questa loro non dimostrabilità le avvolge di mistero. Facciamo un piccolo recap.

Assiomi o postulati

Sono delle affermazioni così elementari che non possono essere dedotte da affermazioni ancora più semplici. A volte non sembrano molto elementari però si decide di arrestare il processo deduttivo perché non porterebbe più da nessuna parte se non girare il discorso utilizzando dei sinonimi. Ad esempio Assioma I della geometria euclidea:

Tra due punti qualsiasi è possibile tracciare una e una sola retta.

Qui si potrebbe obiettare “cos’è la retta? cos’è un punto? Il mio professore di Analisi I, Ezio Stagnaro, ci fece questo esempio:

Potete sostituire alla parola “punto” la parola “scarpe” e alla parola “retta” la parola “uomo” e verificare se detto così l’assioma funziona. Se poi riuscite a far funzionare l’analogia per tutti gli altri assiomi, vi accorgerete che punti e rette non sono oggetti in sé ma possono essere istanziati nella realtà in qualunque modo questo consenta di non pervenire a contraddizioni.

Proposizioni e teoremi

A partire dai fatti elementari (assiomi) costruiamo affermazioni più complesse (“La somma degli angoli interni di un triangolo è congruente con un angolo piatto” per rimanere nella Geometria Euclidea) che fanno discedere un fatto complesso (tesi) ad un certo numero finito di premesse (ipotesi). Il processo deduttivo che porta dalle ipotesi alla tesi senza saltare passaggi è detto dimostrazione del teorema. Se un teorema ha una dimostrazione l’affermazione è vera all’interno del sistema assiomatico e non può essere negata.

… e le congetture?

Se non riusciamo a trovare la dimostrazione siamo in una terra di mezzo. La proposizione è verificata in un numero più o meno grande di casi, sembra tenere, ma siccome non si possono provare tutti gli infiniti casi, non possiamo essere certi che funzioni sempre. Questa sicurezza ce la può dare solo una dimostrazione rigorosa.

Gli attacchi che i matematici sferrano verso queste proposizioni “maledette” a volte hanno qualcosa di epico, perché sono in grado di resistere per secoli all’assalto di menti sopraffine.

Per citarne un’altra di celebre, oltre a quella di Collatz, basti la congettura di Riemann, secondo la quale gli zeri non banali della funzione Zeta di Riemann hanno tutti parte reale uguale a 1/2. Anche di questa non si è ancora trovata una dimostrazione, benché fosse uno dei problemi inseriti da David Hilbert nell’elenco dei 23 problemi ancora da risolvere alla fine del XIX secolo (il problema numero 8, per la precisione).

Non è nemmeno provato che queste proposizioni non si possono dimostrare, almeno ci si metterebbe l’anima in pace. La proverbiale “pietra sopra” ad esempio è stata messa in un caso famoso: dopo secoli di tentativi da parte di matematici più o meno bravi di fornire una dimostrazione, si è trovato che l’assioma 5 della geometria euclidea – l’assioma delle parallele – non si poteva dimostrare come se fosse un teorema ma che anzi si poteva anche negare, addirittura in due modi, originando due nuovi sistemi indpendenti: le due geometrie non euclidee, quella di Riemann e quella di Bolyai/Lobacevskij.

In generale è stato dimostrato da Kurt Gödel che questo assioma è un punto debole come un punto debole ce l’ha qualsiasi altro sistema assiomatico (teoremi di incompletezza). Quindi in questo Gödel ha messo una pietra sopra sul fatto che in ogni sistema assiomatico ci sia un’affermazione che non può essere né dimostrata né negata all’interno dello stesso sistema.

Infatti si costruisce un altro sistema con una negazione del V postulato che ad esempio generi la geometria iperbolica e anche all’interno di questa non è dimostrabile né confutabile. Lo stesso vale per la geometria ellittica.

Non c’è niente da fare. Però questo teorema ha fatto finalmente in modo che la questione si potesse considerare chiusa una volta per sempre.

Ma in questo caso invece, come disse Paul Erdős, matematico ungherese, a proposito della congettura di Collatz

“La matematica non è ancora pronta per risolvere problemi del genere”

Paul Erdős

La congettura

La congettura di Collatz afferma che la successione così definita:

	x_{n+1} = 
	\begin{cases}
	3x_n + 1, & x_n \mod 2 = 0 \\
	x_n/2 & x_n \mod 2 = 1
	\end{cases}

converge sempre a 1 per n \ge N \in \mathbb{N} . Ricordo che x_n \mod 2 = 0 vuol dire che x_n è pari e x_n \mod 2 = 1 vuol dire che x_n è dispari.

Python: la libreria matplotib

Ora per divertirmi un po’ a vedere come funziona questa successione ho utilizzato Python e la libreria matplotlib che avevo già utilizzato per lo studio dell’apprendimento delle reti neurali.

È semplice installarla come libreria stand-alone per Python 3:

$ git clone git@github.com:matplotlib/matplotlib.git
$ cd matplotlib/
$ python3 setup.py install

Sorgente Python

Dopodiché la uso in un programma che semplicemente calcola la successione e la visualizza su un grafico

!/usr/bin/python3
import matplotlib.pyplot as plt

a = input("Dimmi un numero: ")
print("Successione di Collatz a partire da a=",a)
z = int(a)
s = []
s.append(z)

while (z != 1):
   print(z,", ")
   if (z % 2 == 0):
      z /= 2
   else:
      z = 3*z + 1
      
   s.append(z)
# la congettura d Collatz afferma che si esce sempre dal ciclo

# disegna
x = range(len(s))
plt.plot(x, s, label="Successione di Collatz")
plt.xlabel('iterazioni')
plt.ylabel('successione')
plt.title('Congettura di Collatz')
plt.legend() 
plt.grid(True)
plt.show()

Ci si può divertire a vedere il comportamento di questa succcessione che sembra davvero imprevedibile per numeri che non fanno parte della successsione delle potenze di 2. Ad esempio il 103 genera questo andamento

Matematica: Congettura di Collatz: un esempio di successione per punto iniziale x1=103.
Matematica: Successione per x_1= 103

Wi-Fi: come visualizzare la potenza del segnale

Wi-Fi
Wi-Fi

Utilizzo il mio smartphone come hotspot wireless per connettermi a Internet con i dispositivi di casa. Stamattina ho voluto controllare quale fosse la potenza del segnale Wi-Fi perché volevo trovare la posizione ottimale dell’hotspot rispetto alla mia postazione di lavoro.

Prima mi sono studiato come accedere al dato della potenza del segnale Wi-Fiin ingresso dell’antenna (dettagli qui) e poi ho riportato questo dato in funzione del tempo in un grafico animato in modo tale da poter girar per casa e posizionarlo dove ho un segnale più forte, e non è detto che sia accanto al PC 😉

Campionamento della potenza del segnale Wi-Fi

La potenza istantanea del segnale Wi-Fi si può visualizzare con il comando

$ iwconfig wlp2s0
wlp2s0 IEEE 802.11 ESSID:"HUAWEI Y6 2019"
Mode:Managed Frequency:2.412 GHz Access Point: F2:E4:A2:93:8C:0C
Bit Rate=72.2 Mb/s Tx-Power=22 dBm
Retry short limit:7 RTS thr:off Fragment thr:off
Power Management:on
Link Quality=61/70 Signal level=-49 dBm
Rx invalid nwid:0 Rx invalid crypt:0 Rx invalid frag:0
Tx excessive retries:171 Invalid misc:9250 Missed beacon:0

Come si vede, la linea

Link Quality=61/70 Signal level=-49 dBm

contiene l’informazione desiderata. Se spegniamo l’hotspot l’output del comando è invece:

$ iwconfig wlp2s0
wlp2s0 IEEE 802.11 ESSID:off/any
Mode:Managed Access Point: Not-Associated Tx-Power=22 dBm
Retry short limit:7 RTS thr:off Fragment thr:off
Power Management:on

Quindi un modo se volete un po’ grezzo di accedere velocemente alla potenza del segnale Wi-Fi è fare il parsing dell’output di questo comando. L’idea è di lanciarlo con regolarità in modo da costruire un campione di dati da visualizzare in qualche modo in tempo reale.

Il primo programma che ho scritto è questo:

#!/usr/bin/python3
#
# Found in: https://www.calazan.com/how-to-continuously-monitor-your-wi-fis-signal-strength-in-ubuntu/
# Mutatis mutandi
#

import subprocess
import time
import argparse

parser = argparse.ArgumentParser(description='Display WLAN signal strength.')
parser.add_argument(dest='interface', nargs='?', default='wlan0',
                    help='wlan interface (default: wlan0)')
args = parser.parse_args()

print('\n---Press CTRL+Z or CTRL+C to exit---\n')

while True:
    cmd = subprocess.Popen('iwconfig %s' % args.interface, shell=True,
                           stdout=subprocess.PIPE)
                           
    for line in cmd.stdout:
        l = str(line)
        if 'Link Quality' in l:
            print (l),
        elif 'Not-Associated' in l:
            print ('No signal')
    time.sleep(1)

Aspetti importanti di questo script sono il package subprocess che consente a Python di lanciare un comando del sistema operativo, in questo caso

iwconfig wlp2s0

Il package argparser fornisce una serie di utilissime funzioni per maneggiare le linee di comando (definire i parametri di avvio, la loro obbligatorietà, i valori di default e finanche la documentazione di help).

Il package itertools fornisce il metodo count() che realizza un contatore progressivo che ci serve per etichettare i campioni di segnale, campioni che vengono prelevati con regolarità utilizzando le funzione del package time..

In sostanza il metodo subprocess.Popen() lancia il comando e il dato desiderato si trova nell’output del comando che comunque non è una stringa e va convertito per potere fare il parsing. Il parsing si utilizza quando il dato è annegato nella sporcizia, per cui ritengo questo mio metodo un metodo piuttosto sporco.

In questo embrione di programma ho il seguente ouput

—Press CTRL+Z or CTRL+C to stop.—

b' Link Quality=70/70 Signal level=-31 dBm \n'
b' Link Quality=70/70 Signal level=-31 dBm \n'
b' Link Quality=70/70 Signal level=-36 dBm \n'
b' Link Quality=70/70 Signal level=-32 dBm \n'
b' Link Quality=70/70 Signal level=-32 dBm \n'

Il dato interessante si trova in ogni riga dalla posizione 45 alla posizione 48.

Con una piccola modifica ci facciamo stampare solo il dato desiderato

--Press CTRL+Z or CTRL+C to stop.---
-32
-32
-35
-31
-31
-35
-35
-35
-36

Visualizzazione del segnale Wi-Fi utilizzando matplotlib

Ora invece di stampare questi valori, li voglio disporre su un grafico. Utilizzo la libreria matplotlib. Il sorgente completo è il seguente

#!/usr/bin/python3
#
# Adopted for reading wifi power signal and plotting it
#
# @author: marco@betaingegneria.it
# @copyright: GPL Affero v.3
# @date 2020-09-25

import subprocess
import argparse
import matplotlib.pyplot as plt
from itertools import count
from matplotlib.animation import FuncAnimation

# init graphics stuff
plt.style.use('seaborn')

x=[] # time series
y=[] # power samples
index = count()

# init wlan signal reader
# parse line command arguments
parser = argparse.ArgumentParser(description='Display WLAN signal strength.')

# interface
parser.add_argument(dest='interface', nargs='?', default='wlp2s0',
                    help='wireless.py [interface=wlp2s0] [delta=800]')

# sampling period in ms
parser.add_argument(dest='delta', nargs='?', default='800',
                    help='wireless.py [interface=wlp2s0] [delta=800]')
                    
args = parser.parse_args()

if (int(args.delta) < 200):
    print('Please, choose a value >= 200 for delta')
    exit()

print('Close the window to exit')

def animate(i):
    """ read the wifi power in dBm and plot """
    x.append(next(index))
    
    cmd = subprocess.Popen('iwconfig %s' % args.interface, shell=True,
                       stdout=subprocess.PIPE)
                       
    for line in cmd.stdout:
        l = str(line)
        if 'Link Quality' in l:
            y.append(int(l[45:48]))
        elif 'Not-Associated' in l:
            y.append(None)

    plt.cla()
    plt.plot(x, y, '-', marker='.', label='WiFi signal strenght in dBm')
    plt.legend(loc='upper left')
    plt.tight_layout()
    
    # ring a bell every sample
    #print('\a')

ani = FuncAnimation(plt.gcf(), animate, interval=args.delta)    

plt.show()

Un po’ di parafrasi: la funzione animate() contiene il codice che legge la potenza e, eseguendo il parsing estraiamo il valore in dBm da accodare alla lista y, mentre nella lista x accodiamo i valori del contatore.

Il plot viene fatto utilizzando come skin lo stile seaborn, che comprende la griglia in negativo (bianco su grigio).

Infine ho utilizzato il metodo matplotlib.animation() che può essere configurato per un aggiornamento ogni delta millisecondi – ci sganciamo quindi dalla libreria time – , variabile che gestiamo come parametro di input.

Il risultato è questo

Andamento della potenza segnale wireless (max -30dB) provando a spostare l'hotspot in giro per la stanza
Andamento della potenza segnale Wi-Fi provando a spostare l’hotspot in giro per la stanza

Se si spegne l’hotspot o si esce dal suo range di segnale non verrà plottato alcun dato.

Link utili

Lagrangiana

Qualche tempo fa ho acquistato al CERN di Ginevra questa T-shirt che di tanto in tanto indosso:

La lagrangiana del Modello Standard
La lagrangiana del Modello Standard

La formula scritta sulla maglietta è la lagrangiana del modello standard.

Invariabilmente, ogni volta che la indosso, mi chiedono: cos’è una lagrangiana? Oppure cosa vuol dire Modello Standard?

La cosa mi fa piacere perché ragionare di Fisica mi piace sempre un sacco.

La lagrangiana nella Meccanica Classica

Una breve introduzione alla lagrangiana nella Meccanica Classica la trovate qui. Meglio che la leggiate, vi serve per capire un po’ meglio quello che segue.

In sostanza è una funzione di posizione e velocità di un sistema meccanico classico che ci aiuta a scrivere le equazioni del moto.

La lagrangiana in Meccanica Quantistica

La lagrangiana della maglietta è un formalismo che si usa in teoria dei campi ed è l’estensione a questa disciplina del concetto che Lagrange elaborò per risolvere problemi di Meccanica Classica (lui non la chiamava così, siamo noi che abbiamo dovuto attaccare l’aggettivo “classica” per distinguerla dalla Meccanica Relativisitica o dalla Meccanica Quantistica) in sistemi con un numero finito di variabili – o gradi di libertà . Essa dal punto di vista matematico è un oggetto completamente diverso da quello della Meccanica Classica, è una funzione di densità: in questo caso la lagrangiana si applica ai continui e ai campi, che hanno un numero infinito di gradi di libertà.

A grandi linee ogni riga della maglietta è un pezzo della teoria del Modello Standard, il modello che spiega tre delle 4 forze fondamentali dell’Universo:

  • la forza elettromagnetica – che ti fa tenere il cane per il guinzaglio,
  • la forza forte, che tiene insieme i nuclei degli atomi,
  • la forza debole, che permette alle particelle di trasformarsi,

La forza gravitazionale, che ci tiene attacati per terra e move il Sole e l’altre stelle (cit.), finora è la grande esclusa dal Modello Standard.

La lagrangiana prevede 6 termini.

Primo termine -\frac{1}{4}F_{\mu\nu}F^{\mu\nu}

Questo termine è il prodotto scalare del tensore dell’intensità di campo F_{\mu\nu} contenente la codifica matematica di tutte le particelle di interazione – eccetto il bosone di Higgs -, dove \mu e \nu sono indici di Lorentz che rappresentano le componenti dello spaziotempo (t, x, y, z). Contiene la formulazione necessaria affinché queste particelle esistano e descrive come interagiscono tra loro. I contenuti differiscono a seconda delle proprietà delle particelle di interazione. Ad esempio, i fotoni, le particelle di interazione dell’interazione elettromagnetica, non possono interagire tra loro, perché non hanno carica elettrica. Pertanto, il contributo dell’interazione elettromagnetica consiste solo in un termine cinetico, che è la base dell’esistenza di fotoni liberi. La descrizione dei gluoni e dei bosoni dell’interazione debole comprende invece anche i termini di interazione oltre ai termini cinetici. I gluoni, ad esempio, sono essi stessi carichi di “colore” e possono quindi anche interagire tra loro.

Questo porta a una conseguenza entusiasmante: il Modello Standard della fisica delle particelle prevede l’esistenza di stati legati costituiti solo da gluoni, le cosiddette ‘glueballs‘ (letteralmente: palle di colla). Tuttavia, finora nessun esperimento ha rilevato le glueballs.

Il termine i\bar{\psi} D\!\!\!\!/\psi

Questo termine descrive invece come le particelle di interazione interagiscono con le particelle di materia. I campi \bar{\psi} e \psi descrivono (anti)quark e (anti)leptoni. Questo termine ad esempio regola l’annichilazione elettrone-positrone e il decadimento beta.

Il termine h.c.

h.c. sta per hermitian conjugate, coniugato hermitiano: un operatore o una matrice è hermitiana quando il suo prodotto con la controparte complessa coniugata è una quantità reale.

Siccome quando facciamo misure vediamo numeri reali, è necessario che tutte le quantità complesse abbiano il corrispettivo coniugato in modo tale che il prodotto sia un numero reale. Questo è un assioma della Meccanica Quantistica e da’ conto del fatto che le misurazioni sono sempre numeri reali. Il termine h.c. va eventualmente aggiunto al secondo termine (interazione bosone – particella) qualora questo dia un numero complesso. In realtà il secondo termine è sempre un numero reale (più precisamente è un operatore autoaggiunto). Lo chiamano anche hot coffee (caffè che scotta).

Piccolo dizionario: i bosoni (particelle che seguono la statistica di Bose-Einstein)sono le particelle mediatrici della forza (la più famosa è il fotone, che veicola l’interazione elettromagnetica). I fermioni (particelle che seguono la statistica di Fermi-Dirac) sono le particelle di materia ordinaria (protoni ed elettroni per esempio).

Il termine \psi_i y_{ij}\psi_j\phi

Il quarto termine descrive l’accoppiamento di una particella di materia con il campo di Higgs \phi per acquisire massa. y_{ij} è detto campo di Yukawa, vedi bibliografia.

Il termine |D_\mu\phi|^2

Il quinto termine descrive l’accoppiamento di una particella di interazione con il campo di Higgs.

Tuttavia le uniche particelle di interazione (dette anche bosoni) che hanno massa sono i bosoni dell’interazione debole – previste teoricamente da Abdus Salam e scoperte da Carlo Rubbia, per cui questo termine descrive proprio loro (W^{\pm}, Z_0).

Il termine -V(\phi)

L’ultimo termine descrive il potenziale del campo di Higgs (detto più precisamente campo di Brout–Englert–Higgs).

Nella maggior parte delle cose che ci accadono quotidianamente, l’unico termine ad entrare in azione è il secondo. I fotoni non ottengono massa dal meccanismo di Higgs, mentre i gluoni sono privi di massa perché non si accoppiano al campo di Brout-Englert-Higgs.

Come vedete in questa lagrangiana non si parla di gravità. includere la gravità nella teoria di campo quantistica è una delle sfide che stanno impegnando i fisici e i matematici da mezzo secolo e ancora non si vede la luce in fondo al tunnel.

Inoltre il modello standard descrive perfettamente la materia, ma ciò che vediamo è solo il 5% della materia totale, per cui il resto cos’è e come funziona?

Per chi volesse approfondire, in bibliografia c’è un bell’articolo, senza addentrarsi troppo nei dettagli.

Fatemi siete arrivati fin qui se vi è piaciuto l’articolo.

Ringrazio Corrado Tagliente per avermi spronato a migliorare l’articolo.

Bibliografia

Pillola Liste Python: quando append() produce una lista di elementi tutti uguali

Liste Python: l'uso del metodo append()
Liste Python: l’uso del metodo append()

Liste Python: provando a costruire una lista, con un metodo learn di una certa classe P che ritorna una lista

for i in range(1,5):
    w=P.learn()
    print(type(w))
    hist_w.append(w)
    print("hist_w", hist_w)

i valori di w ritornati ad ogni ciclo erano del tipo

[-1.7968410695441766, 1.1, 0.20315893045582345]
[-2.4943448781251716, 1.1, -0.4943448781251717]

ma la lista hist_w al primo ciclo conteneva

[[-1.7968410695441766, 1.1, 0.20315893045582345]]

Al secondo ciclo conteneva

[[-2.4943448781251716, 1.1, -0.4943448781251717],
[-2.4943448781251716, 1.1, -0.4943448781251717]]

e così via, cioè anziche venire aggiunto l’ultimo elemento (anche lui una lista) alla lista, venivano sostituiti tutti gli elementi della lista con l’ultima lista calcolata.

Il problema è che stavo copiando ogni volta il riferimento alla variabile w (che è lo stesso ad ogni ciclo) e non il contenuto della variabile stessa (che cambia ad ogni ciclo):

[<riferimento a w>, <riferimento a w>, …]

Per disinnescare l’errore ho fatto così:

for i in range(1,5):
    w=P.learn()
    print(type(w))
    hist_w.append(w[:])
    print("hist_w", hist_w)

Notate il [:] accanto al nome della variabile.

Liste Python: altre risorse utili

Strutture dati Python

Git in pillole: il file .gitignore

gitignore
git

.gitignore o .git/info/exclude? Vediamo le differenze e il perché a volte Git sembra ignorare le nostre direttive sull’esclusione di alcuni file dal ciclo di vita del software.

Differenza tra .gitignore e .git/info/exclude

Entrambi i file servono a Git per stabilire quali file non entrano nel ciclo di versionamento.

Essi agiscono ad un diverso livello.

Il file .git/info/exclude serve per escludere i file nel proprio clone locale; se qualcuno che collabora con noi non ha escluso gli stessi file che abbiamo escluso noi, potremmo ritrovarci – se facciamo un clone o un fetch – file che sono entrati nel versionamento nell’origin ma che io non ho perché esclusi, o viceversa. Quindi è bene, quando si devono escludere dei file globalmente (per tutti i programmatori) agire sul file .gitignore che invece viene versionato – per cui ogni repository locale se lo trova. Se dobbiamo agire in modo più granulare sui file da versionare (o meno) directory per directory, è possibile scrivere un apposito file .gitgnore in ogni directory in cui serve.

Git sembra ignorare la direttiva di ignorare file

Ho messo dei file da escludere nel file .git/info/exclude (o in .gitignore) ma continuo a vederli come new file quando eseguo il comando git status:

$ git status
Sul branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   app/Http/Controllers/BaseController.php
        new file:   storage/logs/laravel-2020-07-22.log
        new file:   storage/logs/laravel-2020-07-23.log
        ...
  

In particolare non voglio che i file di log entrino nel versionamento. Ho però inserito correttamente la riga

storage/logs*

in entrambi i file .gitignore e .git/info/exclude. Come mai Git continua a mostrarmeli come file da versionare?

Git utilizza il file .gitignore nel momento in cui aggiunge i file; una volta aggiunti all’indice dei file da versionare Git continua a considerarli tali, a dipetto di modifiche successive dei file di gitignore. Quindi ci sono due modi per uscire dall’impasse:

  • cancellare fisicamente i file, ma è l’opzione più stupida
    git rm storage/logs/*
  • cancellare la cache:
    git rm --cached storage/logs/*

Infatti l’opzione --cached indica a Git di togliere i file dall’indice ma non dal file system.

Ho trovato queste indicazioni in un paio di risposte di fourm 1 e 2.

Altri articoli del blog su git