mercoledì 29 marzo 2023

PostgresSql partitioning

Una delle funzioni meno comuni di Postgres e' quella di effettuara il partiniong di una tabella per velocizzare il tempo di accesso. In sintesi si puo' suddividere una tabella di generose dimensione sulla base di un criterio (data, indice numerico intero) in sotto tabelle senza modificare la query di interrogazione della tabella madre. Non tutte le strutture dati sono idonee al partizionamento (per esempio quando ci sono solo campi stringhe)

In pratica si puo' creare un partitioning inserendo il campo che si vuole utilizzare per il partitioning

CREATE TABLE public.partizione (

    code character varying(12),
    vel real,
    v_stdev real,
  ....
    objectid integer NOT NULL,
    the_geom public.geometry(Point,32633)
) PARTITION BY RANGE(objectid);

 si creano quindi le sottotabelle con gruppi di 20000....attenzione che se il valore del campo di partizionamento eccede il valore massimo la riga non verra' inserita...per esempio inserire un campo con objectid=290000 generera' errore con la regola sottostante

CREATE TABLE partizione_0 PARTITION OF partizione FOR VALUES FROM (1) TO (20000);
CREATE TABLE partizione_1 PARTITION OF partizione FOR VALUES FROM (20001) TO (40000);
CREATE TABLE partizione_2 PARTITION OF partizione FOR VALUES FROM (40001) TO (60000);
CREATE TABLE partizione_3 PARTITION OF partizione FOR VALUES FROM (60001) TO (80000);
CREATE TABLE partizione_4 PARTITION OF partizione FOR VALUES FROM (80001) TO (100000);
CREATE TABLE partizione_5 PARTITION OF partizione FOR VALUES FROM (100001) TO (120000);
CREATE TABLE partizione_6 PARTITION OF partizione FOR VALUES FROM (120001) TO (140000);
CREATE TABLE partizione_7 PARTITION OF partizione FOR VALUES FROM (140001) TO (160000);
CREATE TABLE partizione_8 PARTITION OF partizione FOR VALUES FROM (160001) TO (180000);
CREATE TABLE partizione_9 PARTITION OF partizione FOR VALUES FROM (180001) TO (200000);
CREATE TABLE partizione_10 PARTITION OF partizione FOR VALUES FROM (200001) TO (220000);
CREATE TABLE partizione_11 PARTITION OF partizione FOR VALUES FROM (220001) TO (240000);
CREATE TABLE partizione_12 PARTITION OF partizione FOR VALUES FROM (240001) TO (260000);
CREATE TABLE partizione_13 PARTITION OF partizione FOR VALUES FROM (260001) TO (280000);

Per interrogare la tabella si usa SELECT..FROM TABLE partizione...sara' poi il motore del DB ad andare a trovare la sottotabella corrispondente

Ho cercato di misurare l'aumento delle prestazione del database ma ho avuto risultati variabili anche a causa di non riuscire a controllare la cache...indicativamente il miglior risultato e' stata un diminuzione dei tempi del 30%

giovedì 16 marzo 2023

Phishing via SMS 2023

 Una variante interessante rispetto al precedente esempio di phishing via SMS visto in precedenza 

Questa volta e' stato piu' insidioso perche' viene indicata la consegna di un pacco ad un centro di ritiro...plausibile...chi e' che non riceve pacchi oggi


Andando al link viene segnalata la necessita' di pagare 2 euro di tasse doganali (plausibile...mi e' capitato di ricevere pacchi dall'estero con la necessita' di pagare le tasse)




Mi sono insospettito quando mi veniva richiesto di reinserire i miei dati personali (del resto il corriere li doveva gia' conoscere....ho guardato il sito awardau.live..e sono passato ad aprire il link sul computer per vedere i sorgenti della pagina. La cosa divertente e' andando a www.awardau.live veniva proposto una spedizione di DHL mentre il link dell'SMS indicava una spedizione GLS


Capito l'ingannno ho provato a vedere come funziona la truffa....dopo aver cliccato sul sito awardau.live si veniva instradati su Pagamento Sicuro (ovviamente finto) in cui vengono richieste tutte le informazioni sulla carta di credito (ovviamente non era presente il pagamento via Paypal) compreso il CIN.

Nel codice HTML oltre a riferimenti a JQuery era presente il link a https://track.fwdtrck.com/click
(il link e' disattivo al momento in cui scrivo) ed a pro.ip-api.con con una key scaduta





Pulsante Dyson V10

 Pagare oltre 400 euro per avere un aspirapolvere e dopo tre anni essere costretti a smontarlo per la rottura di pezzo di plastica (il pulsante) da pochi centesimi di euro non fa certo piacere....fra le altre cose per la riparazione si deve smontare praticamente tutto il dispositivo (e si deve almeno una chiave torx con prolunga)

Il pezzo di ricambio corregge la debolezza di progettazione iniziale





mercoledì 15 marzo 2023

Local Packages in Golang

 Per poter utilizzare packages locali (librerie di funzioni create dall'utente esterno racchiuse in un package esterno al main) la soluzione e' inserire i le librerie esterne nel subfolder /vendor



nel file main.go l'importazione avviene semplicemente inserendo in import il nome del file della libreria e richiamando le funzioni della libreria come metodi 


import (
    "fmt"
    "scrivi"
)

func main() {
    fmt.Println("luca")
    scrivi.Debug(true)
    scrivi.Log("log")
}


lunedì 13 marzo 2023

Restful server in GO

Un esempio di server Restful con la libreria  go-restful

Nelle note del codice alcune indicazioni su come interagire con il server che si apre su porta 8080


// Pacchetto per utilizzo di Restfull
package main

// inserisci nuovo utente
// curl -X POST -H "Content-Type: application/json" -d '{"Id": "42", "Name": "Luca Innocenti"}' http://localhost:8080/users/
// update utente
// curl -X PUT -H "Content-Type: application/json" -d '{"Id": "42", "Name": "Luca Innocenti"}' http://localhost:8080/users/
// cancella utente con id 42
// ricerca utente con id 42
// curl -X "GET"  http://localhost:8080/users/42

//curl -vX POST http://server/api/v1/places.json -d @testplace.json

import (
    "fmt"
    "log"
    "net/http"

    restful "github.com/emicklei/go-restful/v3"
)

// User is a struct
type User struct {
    Id, Name string
}

// Fprint formats using the default formats for its operands and writes to w.
// Spaces are added between operands when neither is a string.
func New() *restful.WebService {
    service := new(restful.WebService)
    service.
        Path("/users").
        Consumes(restful.MIME_XML, restful.MIME_JSON).
        Produces(restful.MIME_XML, restful.MIME_JSON)

    service.Route(service.GET("/{user-id}").To(FindUser))
    service.Route(service.POST("").To(CreateUser))
    service.Route(service.PUT("/{user-id}").To(UpdateUser))
    service.Route(service.DELETE("/{user-id}").To(RemoveUser))

    return service
}

// GET
func FindUser(request *restful.Request, response *restful.Response) {
    id := request.PathParameter("user-id")
    // here you would fetch user from some persistence system
    usr := User{Id: id, Name: "Luca"}
    response.WriteEntity(usr)
}

// PUT /user-id
func UpdateUser(request *restful.Request, response *restful.Response) {
    parametri := User{Id: request.PathParameter("user-id")}
    //fmt.Println("udpdate user")
    fmt.Println("Numero " + parametri.Id + "Nome " + parametri.Name)
    usr := new(User)
    err := request.ReadEntity(&usr)
    // here you would update the user with some persistence system
    if err == nil {
        response.WriteEntity("modificato")
    } else {
        response.WriteError(http.StatusInternalServerError, err)
    }
}

// POST

func CreateUser(request *restful.Request, response *restful.Response) {
    usr := new(User)
    err := request.ReadEntity(&usr)
    // here you would create the user with some persistence system
    if err == nil {
        response.WriteEntity(usr)
    } else {
        response.WriteError(http.StatusInternalServerError, err)
    }
}

// DELETE /user-id

func RemoveUser(request *restful.Request, response *restful.Response) {
    fmt.Println(request.PathParameter("user-id"))
    log.Printf("DELETE")
    // here you would delete the user from some persistence system
}

func main() {
    restful.Add(New())
    log.Fatal(http.ListenAndServe(":8080", nil))
}






venerdì 10 marzo 2023

cUrl is not cUrl in Windows 10

 Usando praticamente mai Windows come ambiente di sviluppo ed ho scoperto a mie spese che il comando curl installato di default su Windows 10 non e' lequivalente di curl su Linux ma un alias di un comando di PowerShell con una sintassi differente

mercoledì 8 marzo 2023

Formaldeide e metano da Sentinel 5 con Google Earth Engine

 Usare Google Earth Engine per Sentinel 5 e' comodo perche' i pixel sono stati ricalcolati in modo omogeneo (nei file netcdf originali i pixel hanno dimensioni differenti a secondo dell'orbita)

I valori di CH4 sono espressi in ppm ed il range di valore e' estremamente stretto (da 1860 a 1890 ppm nell'immagine ) con la dimensione del pixel di 1113 m. I dati sono disponibili sono per le aree di fondovalle




I dati di formaldeide sono espressi in mol/m2 ed il range di valori varia tra 0.00007 e 0.00014 con pixel di 1113 m. 




var palettes = require('users/gena/packages:palettes');
  
var palette_r = palettes.colorbrewer.Accent[5];
var collection = ee.ImageCollection('COPERNICUS/S5P/NRTI/L3_HCHO')
  .select('tropospheric_HCHO_column_number_density')
  .filterDate('2019-01-01', '2019-12-31');
var median = collection.reduce(ee.Reducer.mean());
var band_viz = {
  min: 0.00007,
  max: 0.00014,
  palette: ['black', 'blue', 'purple', 'cyan', 'green', 'yellow', 'red']
};
Map.addLayer(collection.mean(), band_viz, 'S5P HCHO');
Map.setCenter(11.295553516712024, 43.976202446636606,9);
Map.style().set('cursor', 'crosshair');
var header = ui.Label('HCHO', {fontWeight: 'bold', fontSize: '18px'});
var toolPanel = ui.Panel([header], 'flow', {width: '400px'});
Map.onClick(function(coords) {
  // Create or update the location label (the second widget in the panel)
  var location = 'lon: ' + coords.lon.toFixed(4) + ' ' +
                 'lat: ' + coords.lat.toFixed(4);
  var click_point = ee.Geometry.Point(coords.lon, coords.lat);
  var CH4Value = median.reduceRegion(ee.Reducer.first(), click_point, 90).evaluate(function(val){
    console.log(val);
    var CH4Text = 'CH4: ' + val;
    toolPanel.widgets().set(2, ui.Label(CH4Text));
  });
  
  toolPanel.widgets().set(1, ui.Label(location));
  // Add a red dot to the map where the user clicked.
  Map.layers().set(1, ui.Map.Layer(click_point, {color: 'FF0000'}));
});
// Add the panel to the ui.root.
ui.root.add(toolPanel);

Posizione date le distanze da due punti conosciuti

 Un problema che si ha con il posizionamento decawave e' quello di ottenere la posizione (coordinate) data la distanza da due punti conosciuti

Alla fine il problema si riduce ad ottenere gli angoli di un triangolo di cui sono conosciute le lunghezze di tutti i lati


diciamo che il lato A sia la distanza tra i due anchor mentre C e B sono le distanze del tag rispetto ai due anchor

Tutti i lati possono essere riscritti come

A = Ccos(alfa)+Bcos(beta)

B = Acos(beta)+Ccos(gamma)

C=Acos(alfa)+Bcos(gamma)

si tratta si un sistema di tre equazioni con 3 incognite e quindi risolvibile. Per semplice sostituzione si arriva alla fine che

cos(beta) = (A*A)+(B*B)-(C*C)/2AB

cos(alfa) = (A*A)+(C*C)-(B*B)/2AC

cos(gamma) = (B*B)+(C*C)-(A*A)/2BC

a questo punto abbiamo tutti gli angoli. Si puo' spostare un anchor sulle origine degli assi e ruotare gli assi in modo che il secondo anchor sia in coordinata (x2,0)

A questo punto le coordinate incognite del punto tra B e C sono

X = Bcos(alfa)

Y = SQRT(1 - cos(alfa)*cos(alfa))





martedì 7 marzo 2023

Makerfabs DW3000

Aggiornamento

Frugando meglio nei sorgenti della libreria ho visto che sono previste 33 configurazioni dell'antenna in base al tranfer rate, alla lunghezza dei pacchetti ed altro. Di default e' attivato il profilo 33 che non risulta essere adatto per le lunghe distanze


Ho quindi modificato il file dw3000_config_options.h della libreria alla riga 240 con 

#define CONFIG_OPTION_16

che corrisponde alla impostazione

/* Configuration option 16.
 * Channel 9, PRF 64M, Preamble Length 1024, PAC 8, Preamble code 10, Data Rate 850k, STS Length 64
 */
dwt_config_t config_options = {
    9,                  /* Channel number. */
    DWT_PLEN_1024,      /* Preamble length. Used in TX only. */
    DWT_PAC8,           /* Preamble acquisition chunk size. Used in RX only. */
    10,                  /* TX preamble code. Used in TX only. */
    10,                  /* RX preamble code. Used in RX only. */
    3,                  /* 0 to use standard 8 symbol SFD, 1 to use non-standard 8 symbol, 2 for non-standard 16 symbol SFD and 3 for 4z 8 symbol SDF type */
    DWT_BR_850K,        /* Data rate. */
    DWT_PHRMODE_STD,    /* PHY header mode. */
    DWT_PHRRATE_STD,    /* PHY header rate. */
    (1024 + 1 + 8 - 8),  /* SFD timeout (preamble length + 1 + SFD length - PAC size). Used in RX only. */
    DWT_STS_MODE_1,      /* Mode 1 STS enabled */
    DWT_STS_LEN_64,      /* STS length*/
    DWT_PDOA_M0         /* PDOA mode off */
};
#endif

in pratica ho impostato il valore piu' basso di transfer rate (850Kbps con il pacchetto di preambolo della massima lunghezza ed abilitando STS. La modalita' STS (scrambled timestamp sequence) migliora la qualita' della stima della distanza impedendo interferenze


Ho utilizzato gli sketch di initiator e responder negli esempi della libreria ex_06a_ss_twr_initiator_sts e ex_06a_ss_twr_responder_sts senza modifiche

Da una serie di 1850 misure statiche la standard deviation e' risultata intorno ai 4 cm 


Ho provato a vedere spostando di 3 cm per volta se riuscivo ad osservare lo spostamento (teoricamente non doveva essere possibile perche' la sensibilita' e' data genericamente intorno ai 10 cm dalla ditta)

Pos 1 : 930 misure Media 2.66 m StDev 0.062 m


Pos 2  (Pos1 + 3 cm) : 670 misure Media 2.71 m StDev 0.025 m


Pos 2  (Pos1 + 7 cm) : 1480 misure Media 2.72 m StDev 0.027 m



Un primo aspetto da indicare e' che la distribuzione dei dati non risulta particolarmente simmetrica rispetto al valore medio 

Con questa configurazione sono arrivato a ricevere fino a circa 12 m di distanza  

==================================================================

Ho avuto modo di provare la scheda Makersfab Dw3000 basata su un Esp32 a cui e' collegata una antenna Decawave UWB Dw3000 (3110 per l'esattezza) che permette il calcolo della distanza tramite il calcolo del tempo di doppia percorrenza di un segnale tra due antenna (una chiamata initiator responsabile dell'invio dello scambio e ed un responser)...esiste una versione che usa la differenza di fase 


Questo metodo di calcolo del tempo di volo permette di non necessitare la sincronizzazione degli orologi delle due schede


Note estremamente dolenti...rispetto alla versione Dw1000 sempre di Makerfabs al momento il supporto software e di documentazione e' al limite dell'inesistente. Nella libreria Arduino ci sono alcuni esempi poco commentati (per avere informazioni meglio riferirsi all'SDK ufficiale )

Ho fatto qualche prova con lo sketch ex_06a_ss_twr_initiator_sts_no_data ma la distanza stimata e' molto instabile con variazione di circa 10 cm (e fino a qui rientra nell'errore dichiarato del sensore) ma molto sensibile anche dalla presenza di oggetti nell'intorno. Non sono stato in grado di avere una retta di calibrazione

Un altro aspetto che non riesco a gestire e' la potenza del segnale. A questo link viene indicato che si possano registrare pacchetti fino a circa 20 m di distanza mentre con i miei moduli non riesco ad allontanarmi oltre i 5 m

Alla fine non sono riuscito a capire se l'insuccesso e' relativo ad un difetto delle mie schede o qualche programmazione non corretta (ma di fatto ho usato gli sketch di esempio)

venerdì 3 marzo 2023

Telit GE864-PY

Mi e' stato regalato una volta dismesso questo dispositivo nato per leggere una seriale ed inviare i dati via rete cellulare 


Pensavo di poter recuperare qualche componente ma tutte le funzioni sono integrate nell'unico chip



Seagate ST-251

 Il mio piccolo museo dell'informatica ha avuto una nuova acquisizione, un hard disk Seagate ST-251 del 1990

Si tratta di un HD da 42 Mb formattato che ha connettori MTM e non IDE. Non ho il controller adatto per cui non ho la piu' pallida idea se sia funzionante (ma guardando su Internet sembra che questi dispositivi fossero particolarmente delicati e pochi sono sopravvissuti funzionanti)







mercoledì 1 marzo 2023

PIP Python error: externally-managed-environment

 Da qualche tempo sulla mia Debian testing non riesco ad installare le librerie Python tramite PIP ma sono tramite APT a causa dell'errore

error: externally-managed-environment

× This environment is externally managed
╰─> To install Python packages system-wide, try apt install python3-xyz, where xyz is the package you are trying to install.


l'unico modo per risolvere e' quello di usare un venv od usare PyCharm che in automatico crea un venv per ogni progetto

Change detection con Open3D su nuvole di punti

Anche la libreria Open3D ha una funzione che permette di calcolare la distanza tra due nuvole di punti anche se non e' esplicitato l'algoritmo (inoltre per i punti in cui non c'e' sovrapposizione immediata il codice del precedente post riporta NaN mentre qui un valore di distanza viene sempre proposto. Inoltre la matrice delle distanze contiene solo valori positivi



I risultati mi sembrano migliori quelli dell'algoritmo del precedente post

import numpy as np
import laspy as lp
import open3d as o3d

p2019= lp.read("2019.las")

points_2019 = np.vstack((p2019.x, p2019.y, p2019.z)).transpose()
#colors_2019 = np.vstack((p2019.red, p2019.green,p2019.blue)).transpose()

pcd2019 = o3d.geometry.PointCloud()
pcd2019.points = o3d.utility.Vector3dVector(points_2019)
#pcd2019.colors = o3d.utility.Vector3dVector(colors_2019 / 65535)


p2022 = lp.read("2022.las")

points_2022 = np.vstack((p2022.x, p2022.y, p2022.z)).transpose()
#colors_2022 = np.vstack((p2022.red, p2022.green,p2022.blue)).transpose()

pcd2022 = o3d.geometry.PointCloud()
pcd2022.points = o3d.utility.Vector3dVector(points_2022)
distance=pcd2019.compute_point_cloud_distance(pcd2022)

rows, columns = points_2019.shape

reds = np.empty(rows)
blues = np.empty(rows)
greens = np.empty(rows)


for i in range(0,rows):
#print(t)
if (distance[i]< -1.5):
Red = 255
Green = 0
Blue = 0

if ((distance[i]>=-1.5) and (distance[i]<=-0.75)):
Red = 255
Green = 255
Blue = 0

if ((distance[i]>=-0.75) and (distance[i]<=0.75)):
Red = 0
Green = 255
Blue = 0
if ((distance[i]>=0.75) and (distance[i]<=1.5)):
Red = 0
Green = 255
Blue = 255

if (distance[i]> 1.5):
Red = 0
Green = 0
Blue = 255
if (distance[i]> 10):
Red = 0
Green = 0
Blue = 0

if (distance[i]< 10):
Red = 0
Green = 0
Blue = 0

reds[i]= Red
greens[i]= Green
blues[i]=Blue

header = lp.LasHeader(point_format=3, version="1.2")
las = lp.LasData(header)

las.x = points_2019[:,0]
las.y = points_2019[:,1]
las.z = points_2019[:,2]
las.red = reds[:]
las.blue = blues[:]
las.green = greens[:]
las.write("open3d_result.las")






Eth0 su LuckFox Pico Mini A

 Le schede Luckfox Pico Mini A (a differenza delle sorelle maggiori) non hanno un connettore RJ45 e nonostante i pin da saldare non sembrano...